private static Node<string> BFSGetGoalParent(MyGraph<string> graph, Node<string> rootNode, Node<string> goalNode) { // Create a queue to keep track of search Queue<Node<String>> q = new Queue<Node<string>>(); q.Enqueue(rootNode); rootNode.Visited = true; //Visiting children each level at a time while (!(q.Count == 0)) { Node<string> n = q.Dequeue(); Node<string> child = null; //Check each child before moving on to the next level while ((child = getUnvisitedChildNode(n)) != null) { q.Enqueue(child); child.Visited = true; if (child == goalNode) { clearNodes(graph); return n; } } } return null; }
private void rangeFunction(Node lookAt) { if (lookAt.isWalkable()) { // adds node to range pairs if not present already. if (!nodesInRangeSet.Contains(lookAt)) { nodesInRangeSet.Add(lookAt); nodesInRange.Add(lookAt); } bool frendType = uRef.isEnemy(); // targets! if (lookAt.Occupied && lookAt.Occupier.isEnemy() != frendType) { currentTargets.Add(new Node.NodePointer(shootingFrom, lookAt, Node.range(shootingFrom, lookAt))); } if (reverseNodesInRangeSetCost.ContainsKey(lookAt)) { if (reverseNodesInRangeSetCost[lookAt] > shootingFrom.realCost) reverseNodesInRangeSetCost[lookAt] = (int) shootingFrom.realCost; } else reverseNodesInRangeSetCost.Add(lookAt, (int) (shootingFrom.realCost)); } }
private void initialize(Node start, float endurance) { pathFinderRef.nodesThatSatisfyPred(start, pathfindPredicate, endurance); foreach (Node n in nodesCanWalkTo) { shootingFrom = n; pathFinderRef.runFuncOnAllNodesInRangeOfNode(shootingFrom, uRef.getMinAttackRange(), uRef.getMaxAttackRange(), rangeFunction); } }
public void CreateEdges(int num_edges) { Console.WriteLine("================================================================"); Console.WriteLine("Creating " + num_edges + " edges"); const int RANDOM_SEED = 55555; DateTime dt = DateTime.Now; Node from = new Node(); Node to = new Node(); for (int z = 0; z < (5 * num_edges); z++) { // Get two random nodes from node_list Random rand = new Random(RANDOM_SEED + z); int r = rand.Next(node_list.Count); //Console.WriteLine("First r = " + r); from = searchNode(r); // get one more random number r = rand.Next(node_list.Count); //Console.WriteLine("second r = " + r); to = searchNode(r); // dont allow self loops as of now if (from.node_id == to.node_id) { r = rand.Next(node_list.Count); to = searchNode(r); } // avoid creating duplpicate edges between nodes if(isEdge(from.node_id, to.node_id)) { Console.WriteLine("Avoiding duplicate edges"); r = rand.Next(node_list.Count); to = searchNode(r); } //now we have 2 random nodes. see if we can hook up these two Waxman w = new Waxman(); double value = 0.0; double compare = 0.0; compare = rand.NextDouble(); value = w.ProbFunc(from, to); //Console.WriteLine("Compare = " + compare + " value = " + value); Random rndm = new Random(); if (value < compare) { int rndm_num = rand.Next(1, 100); Console.WriteLine("Connecting edge from " + to.node_id + " to " + from.node_id + " with cost = " + rndm_num); from.addAdjNode(to, rndm_num); to.addAdjNode(from, rndm_num); } } }
public double ProbFunc(Node src, Node dest) { double distance, L, alpha, beta; alpha = 0.15; beta = 0.2; int x1, x2, y1, y2, dx, dy; x1 = src.Xpos; x2 = dest.Xpos; y1 = src.Ypos; y2 = dest.Ypos; dx = x2 - x1; dy = y2 - y1; distance = Math.Sqrt(dx * dx + dy * dy); //Console.WriteLine("Distance between " + src.node_id + " and " + dest.node_id + " = " + distance); L = Math.Sqrt(2) * MAX_X; /*Console.WriteLine("distance = " + distance); Console.WriteLine("L = " + L);*/ //Console.WriteLine("final value = " + (alpha * Math.Exp(-1.0 * (distance / (beta * L))))); return 10 * alpha * Math.Exp(-1.0 * (distance / (beta * L))); }
/// <summary> /// Initializes the graph. /// Important: Since this uses physics, we cannot use a constructor. /// Instead, we have to call this on the already constructed object. /// </summary> /// <param name="lowLeftBound">The lower left bound of the map in world space.</param> /// <param name="upRightBound">The upper right bound of the map in world space.</param> /// <param name="pathWidth">How wide to make the path. Smaller values mean we can place nodes in tighter spaces.</param> /// <param name="nodeDensity">How dense the nodes should be. Smaller values mean less nodes are placed.</param> /// <param name="startPos">The starting seed position of the graph.</param> public void initializeGraph(Vector2 lowLeftBound, Vector2 upRightBound, float pathWidth, float nodeDensity = 1.0f, Vector2 startPos = new Vector2()) { lowerLeftBound = lowLeftBound; upperRightBound = upRightBound; this.nodeDensity = nodeDensity; // Determine proper numbers of nodes in the x direction. float xDist = lowerLeftBound.x - upperRightBound.x; int xDensity = Mathf.CeilToInt(Mathf.Abs(xDist * nodeDensity)); // Same, but for y direction. float yDist = upperRightBound.y - lowerLeftBound.y; int yDensity = Mathf.CeilToInt(Mathf.Abs(yDist * nodeDensity)); numXNodes = xDensity; numYNodes = yDensity; // Initialize the node array. Note the inverted y, normal x setup. nodeArr = new Node[yDensity][]; for (int i = 0; i < yDensity; i++) nodeArr[i] = new Node[xDensity]; radii = pathWidth / 2.0f; numValidNodes = 0; //floodFill(startPos); fillAll(); isInitialized = true; }
/// <summary> /// Returns a sorted list of nodes within a given endurance value. /// Performs a Dijkstra-like algorithm. /// </summary> /// <param name="satifies">The predicate each node must follow.</param> /// <param name="endurance">The maximum endurance to follow out.</param> /// <returns>A sorted list of nodes within a given endurance value.</returns> public List<Node> nodesThatSatisfyPred(Node startNode, System.Predicate<Node> satifies, float endurance = 16.0f, bool stopOnFirst = false, bool isPathfinding = true) { List<Node> foundNodes = new List<Node>(); MinPriorityQueue<Node> nodeList = new MinPriorityQueue<Node>(); initializePathfinding(isPathfinding); startNode.realCost = 0; nodeList.Enqueue(startNode, startNode.realCost); #if DEBUG_PATHFINDER_LOGDEBUG StringBuilder encountered = new StringBuilder(); StringBuilder nodes = new StringBuilder(); nodes.Append("Start node ").Append(startNode.Number).AppendLine(); encountered.Append("Start node ").Append(startNode.Number).AppendLine(); encountered.Append("endurance = ").Append(endurance).AppendLine(); #endif while (nodeList.Count > 0) { //Pick the best looking node, by f-value. Node best = nodeList.Dequeue(); double bestDist = best.realCost; #if DEBUG_PATHFINDER_LOGDEBUG encountered.Append("Node ").Append(best.Number).Append(" ").Append(best).AppendLine(); nodes.Append("Node ").Append(best.Number).AppendLine(); #endif best.Visited = true; if (satifies(best)) { foundNodes.Add(best); if (stopOnFirst) return foundNodes; } //string updateString = "updating: "; foreach (Edge e in best.getEdges()) { Node other = e.getNode(); //We already visited this node, move along, if (other.Visited) continue; //Tentative distance. double testDist = e.getWeight() + bestDist; if (testDist > endurance) continue; //If the other node isn't in the priority queue, add it. if (!nodeList.Contains(other)) { other.CameFrom = best; other.realCost = testDist; nodeList.Enqueue(other, other.realCost); #if DEBUG_PATHFINDER_LOGDEBUG encountered.Append(" added ").Append(other.Number) .Append(", total estimated cost ") .Append(other.realCost).AppendLine(); #endif continue; } //If the other node was a bad path, and this one's better, replace it. else if (other.realCost > testDist) { other.CameFrom = best; other.realCost = testDist; nodeList.Update(other, other.realCost); #if DEBUG_PATHFINDER_LOGDEBUG encountered.Append(" updated ").Append(other.Number) .Append(", total new estimated cost ") .Append(other.realCost).AppendLine(); #endif } } } #if DEBUG_PATHFINDER_LOGDEBUG Debug.Log(encountered); Debug.Log(nodes); #endif return foundNodes; }
static void Render(Graphics graphics, Node node) { var size = node.bounds.Size; var position = node.bounds.Location; int cornerSize = (int)GraphConstants.CornerSize * 2; int connectorSize = (int)GraphConstants.ConnectorSize; int halfConnectorSize = (int)Math.Ceiling(connectorSize / 2.0f); var connectorOffset = (int)Math.Floor((GraphConstants.MinimumItemHeight - GraphConstants.ConnectorSize) / 2.0f); var left = position.X + halfConnectorSize; var top = position.Y; var right = position.X + size.Width - halfConnectorSize; var bottom = position.Y + size.Height; using (var path = new GraphicsPath(FillMode.Winding)) { path.AddArc(left, top, cornerSize, cornerSize, 180, 90); path.AddArc(right - cornerSize, top, cornerSize, cornerSize, 270, 90); path.AddArc(right - cornerSize, bottom - cornerSize, cornerSize, cornerSize, 0, 90); path.AddArc(left, bottom - cornerSize, cornerSize, cornerSize, 90, 90); path.CloseFigure(); if ((node.state & (RenderState.Dragging | RenderState.Focus)) != 0) { graphics.FillPath(Brushes.DarkOrange, path); } else if ((node.state & RenderState.Hover) != 0) { graphics.FillPath(Brushes.LightSteelBlue, path); } else { graphics.FillPath(Brushes.LightGray, path); } graphics.DrawPath(Pens.DarkGray, path); } /* if (!node.Collapsed) graphics.DrawLine(Pens.Black, left + GraphConstants.ConnectorSize, node.titleItem.bounds.Bottom - GraphConstants.ItemSpacing, right - GraphConstants.ConnectorSize, node.titleItem.bounds.Bottom - GraphConstants.ItemSpacing); */ var itemPosition = position; itemPosition.X += connectorSize + (int)GraphConstants.HorizontalSpacing; if (node.Collapsed) { bool inputConnected = false; var inputState = RenderState.None; var outputState = node.outputState; foreach (var connection in node.connections) { if (connection.To.Node == node) { inputState |= connection.state; inputConnected = true; } if (connection.From.Node == node) outputState |= connection.state | RenderState.Connected; } RenderItem(graphics, new SizeF(node.bounds.Width - GraphConstants.NodeExtraWidth, 0), node.titleItem, itemPosition); if (node.inputConnectors.Count > 0) RenderConnector(graphics, node.inputBounds, node.inputState); if (node.outputConnectors.Count > 0) RenderConnector(graphics, node.outputBounds, outputState); if (inputConnected) RenderArrow(graphics, node.inputBounds, inputState); } else { node.inputBounds = Rectangle.Empty; node.outputBounds = Rectangle.Empty; var minimumItemSize = new SizeF(node.bounds.Width - GraphConstants.NodeExtraWidth, 0); foreach (var item in EnumerateNodeItems(node)) { RenderItem(graphics, minimumItemSize, item, itemPosition); var inputConnector = item.Input; if (inputConnector != null && inputConnector.Enabled) { if (!inputConnector.bounds.IsEmpty) { var state = RenderState.None; var connected = false; foreach (var connection in node.connections) { if (connection.To == inputConnector) { state |= connection.state; connected = true; } } RenderConnector(graphics, inputConnector.bounds, inputConnector.state); if (connected) RenderArrow(graphics, inputConnector.bounds, state); } } var outputConnector = item.Output; if (outputConnector != null && outputConnector.Enabled) { if (!outputConnector.bounds.IsEmpty) { var state = outputConnector.state; foreach (var connection in node.connections) { if (connection.From == outputConnector) state |= connection.state | RenderState.Connected; } RenderConnector(graphics, outputConnector.bounds, state); } } itemPosition.Y += item.bounds.Height + GraphConstants.ItemSpacing; } } }
public NodeEventArgs(Node node) { Node = node; }
public void displayRangeOfUnit(Unit u, Vector2 mousePosition) { clearRangeDisplay(); if (overlayNodes == null) overlayNodes = new List<Node>(); List<Node> reach = nodesWithinEnduranceValue(closestMostValidNode(mousePosition), u.getCurrentWater()); List<Node> range = NodesInRangeOfNodes(reach, u.getMinAttackRange(), u.getMaxAttackRange()); HashSet<Node> inReach = new HashSet<Node>(); inReach.UnionWith(reach); HashSet<Node> inRange = new HashSet<Node>(); inRange.UnionWith(range); inRange.RemoveWhere(inReach.Contains); foreach (Node n in inReach) { //make slightly smaller to show square off Node q = new Node(transform.gameObject, nodeImg, n.getPos(), n.getGridPos(), Node.randWalkState(), radii * 1.75f); q.setColor(new Color(0, 0.5f, 0, 0.75f)); overlayNodes.Add(q); } foreach (Node n in inRange) { //make slightly smaller to show square off Node q = new Node(transform.gameObject, nodeImg, n.getPos(), n.getGridPos(), Node.randWalkState(), radii * 1.75f); q.setColor(new Color(0, 0, 0.5f, 0.75f)); overlayNodes.Add(q); } }
public static void RenderConnections(Graphics graphics, Node node, HashSet<NodeConnection> skipConnections, bool showLabels) { foreach (var connection in node.connections.Reverse<NodeConnection>()) { if (connection == null || connection.From == null || connection.To == null) continue; if (skipConnections.Add(connection)) { var to = connection.To; var from = connection.From; RectangleF toBounds; RectangleF fromBounds; if (to.Node.Collapsed) toBounds = to.Node.inputBounds; else toBounds = to.bounds; if (from.Node.Collapsed) fromBounds = from.Node.outputBounds; else fromBounds = from.bounds; var x1 = (fromBounds.Left + fromBounds.Right) / 2.0f; var y1 = (fromBounds.Top + fromBounds.Bottom) / 2.0f; var x2 = (toBounds.Left + toBounds.Right) / 2.0f; var y2 = (toBounds.Top + toBounds.Bottom) / 2.0f; float centerX; float centerY; using (var path = GetArrowLinePath(x1, y1, x2, y2, out centerX, out centerY, false)) { using (var brush = new SolidBrush(GetArrowLineColor(connection.state | RenderState.Connected))) { graphics.FillPath(brush, path); } connection.bounds = path.GetBounds(); } if (showLabels && !string.IsNullOrWhiteSpace(connection.Name)) { var center = new PointF(centerX, centerY); RenderLabel(graphics, connection, center, connection.state); } } } }
/// <summary> /// Note: This calculates the manhatten distance heuristic. /// </summary> /// <param name="startNode">Start node</param> /// <param name="endNode">End node</param> /// <returns></returns> public float ManhattenHeuristic(Node startNode, Node endNode) { int distX = Mathf.Abs(startNode.getGridPos().x - endNode.getGridPos().x); int distY = Mathf.Abs(startNode.getGridPos().y - endNode.getGridPos().y); return distX + distY; }
/// <summary> /// Reconstructs a path from the end to the start. /// </summary> /// <param name="path">Queue to store path in.</param> /// <param name="end">Ending node in graph</param> private void ReconstructPath(Queue<Node> path, Node end) { path.Clear(); if (end == null) return; Stack<Node> reversePath = new Stack<Node>(); Node cur = end; while (cur != null) { reversePath.Push(cur); cur = cur.CameFrom; } while (reversePath.Count > 0) path.Enqueue(reversePath.Pop()); }
/// <summary> /// Returns a sorted list of nodes within a given endurance value. /// Performs a Dijkstra-like algorithm. /// </summary> /// <param name="endurance">The maximum endurance to follow out.</param> /// <returns>A sorted list of nodes within a given endurance value.</returns> public List<Node> nodesWithinEnduranceValue(Node startNode, float endurance = 16.0f) { //for future reference, less code copy-paste worth negligible performance reduction. return nodesThatSatisfyPred(startNode, (_) => true, endurance); }
/// <summary> /// Performs AStar on the graph. /// </summary> /// <param name="pathStoreLoc">The path will be stored in this queue.</param> /// <param name="startNode">The starting node.</param> /// <param name="targetPos">The target position.</param> public double AStar(Queue<Node> pathStoreLoc, Node startNode, Vector2 targetPos) { if (!isInitialized) throw new UnassignedReferenceException("Pathfinder not initialized yet!"); Node end = closestMostValidNode(targetPos); return AStar(pathStoreLoc, startNode, end); }
public void addNode(int id, int num_nodes) { Node n = new Node(id, num_nodes); node_list.Add(n); }
public void addAdjNode(Node adj, int cost) { Edge edge = new Edge(this, adj, cost); this.edge_list.Add(edge); }
public Edge(Node src, Node dest, int cost) { _src = src; _dest = dest; _cost = cost; }
public AcceptNodeEventArgs(Node node) { Node = node; }
public AcceptNodeEventArgs(Node node, bool cancel) : base(cancel) { Node = node; }
/// <summary> /// Unlike closestMostValidNode; BFS does up to a full BFS /// to find the closest unocupied & walkable node to a given location. /// Only use when not wanting to take into account edge costs. /// If no nodes found that are valid, returns the start node. /// Uses Nodes directly instead of converting from Vector2. /// </summary> /// <param name="startLoc">The location to start looking from.</param> /// <returns>The first unocupied/valid walkable tile found. If no nodes found that are valid, returns the start node.</returns> private Node BFSUnoccupiedAndValid(Node startNode) { if (!startNode.Occupied && startNode.isWalkable()) return startNode; initializePathfinding(true); Queue<Node> listOfNodes = new Queue<Node>(); listOfNodes.Enqueue(startNode); // Can't use visited, as we're already using that hack in initializePathfinding... startNode.realCost = -1; while (listOfNodes.Count > 0) { Node found = listOfNodes.Dequeue(); if (!found.Occupied && found.isWalkable()) return found; foreach (Edge e in found.getEdges()) { Node candidate = e.getNode(); if (candidate.realCost > 0) listOfNodes.Enqueue(candidate); // Can't use visited, as we're already using that hack in initializePathfinding... candidate.realCost = -1; } } return startNode; }
/// <param name="pointTo">Edge to point to.</param> /// <param name="weight">Weight of edge, def = 1.</param> public Edge(Node pointTo, float weight = 1) { this.weight = weight; to = pointTo; }
/// <summary> /// Note: This calculates the diagonal distance heuristic. /// Taken from http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html. /// </summary> /// <param name="startNode">Start node</param> /// <param name="endNode">End node</param> /// <returns></returns> public float DiagonalHeuristic(Node startNode, Node endNode) { float distX = Mathf.Abs(startNode.getGridPos().x - endNode.getGridPos().x); float distY = Mathf.Abs(startNode.getGridPos().y - endNode.getGridPos().y); return distX + distY - (2 - sqrt2) * Mathf.Min(distX, distY); }
public static void RenderConnections(Graphics graphics, Node node, HashSet<NodeConnection> skipConnections, bool showLabels) { if (!node.shown) return; foreach (var connection in node.connections.Reverse<NodeConnection>()) { if (connection == null || connection.From == null || connection.To == null || !connection.From.Node.shown || !connection.To.Node.shown) continue; if (skipConnections.Add(connection)) { var to = connection.To; var from = connection.From; RectangleF toBounds; RectangleF fromBounds; if (to.Node.Collapsed) toBounds = to.Node.inputBounds; else toBounds = to.bounds; if (from.Node.Collapsed) fromBounds = from.Node.outputBounds; else fromBounds = from.bounds; var x1 = (fromBounds.Left + fromBounds.Right) / 2.0f; var y1 = (fromBounds.Top + fromBounds.Bottom) / 2.0f; var x2 = (toBounds.Left + toBounds.Right) / 2.0f; var y2 = (toBounds.Top + toBounds.Bottom) / 2.0f; float centerX; float centerY; int xOffset = GraphConstants.HiddenConnectionLabelOffset; bool isFromNodeHover = (connection.From.Node.state & RenderState.Hover) != 0; bool isConnectionHidden = (connection.state & RenderState.Hidden) != 0; bool isConnectionHover = (connection.state & RenderState.Hover) != 0; using (var path = GetArrowLinePath(x1, y1, x2, y2, out centerX, out centerY, false)) { Color arrowLineColor = GetArrowLineColor(connection.state | RenderState.Connected); if ((connection.state & RenderState.Marked) != 0) { Color glowColorBase = Color.Ivory; Color glowColor = Color.FromArgb( (int)(glowColorBase.A * 0.5), glowColorBase.R, glowColorBase.G, glowColorBase.B); // Draw a glow. var pen = new Pen(new SolidBrush(glowColor), 4.0f); graphics.DrawPath(pen, path); } Brush brush = new SolidBrush(arrowLineColor); if (isConnectionHidden && !isConnectionHover) { if (isFromNodeHover) { graphics.FillPath(new SolidBrush(GetArrowLineColor(RenderState.Hover)), path); } else { graphics.FillRectangle(brush, x1, y1 - 0.75f, xOffset, 1.5f); graphics.FillRectangle(brush, x2 - xOffset, y2 - 2, xOffset, 4); } } else { graphics.FillPath(brush, path); } connection.bounds = RectangleF.Union(path.GetBounds(), connection.textBounds); } if (showLabels && !string.IsNullOrWhiteSpace(connection.Name)) { if (isConnectionHidden) { RenderState rState = isFromNodeHover ? connection.state | RenderState.Hover : connection.state; var center = new PointF(x1, y1); RenderLabel(graphics, connection, center, rState, true); center = new PointF(x2, y2); RenderLabel(graphics, connection, center, rState); } else { var center = new PointF(centerX, centerY); RenderLabel(graphics, connection, center, connection.state); } } } } }
/// <summary> /// A* on the graph. /// </summary> /// <param name="pathStoreLoc">The Queue to store the path in.</param> /// <param name="start">The starting node.</param> /// <param name="end">The ending node.</param> public double AStar(Queue<Node> pathStoreLoc, Node start, Node end, Node toIgnore = null) { MinPriorityQueue<Node> nodeList = new MinPriorityQueue<Node>(); initializePathfinding(true); if (toIgnore != null) toIgnore.Visited = false; System.Func<Node, Node, float> Heuristic; if (allowedPaths == Paths.quadDir) Heuristic = ManhattenHeuristic; else if (allowedPaths == Paths.octDir) Heuristic = DiagonalHeuristic; else Heuristic = DiagonalHeuristic; start.CameFrom = null; start.heuristicCost = Heuristic(start, end); start.realCost = 0; nodeList.Enqueue(start, start.heuristicCost); #if DEBUG_PATHFINDER_LOGDEBUG StringBuilder encountered = new StringBuilder(); StringBuilder nodes = new StringBuilder(); nodes.Append("Start node ").Append(start.Number).AppendLine(); encountered.Append("Start node ").Append(start.Number).AppendLine(); nodes.Append("End node ").Append(end.Number).AppendLine(); encountered.Append("End node ").Append(end.Number).AppendLine(); #endif while (nodeList.Count > 0) { //Pick the best looking node, by f-value. Node best = nodeList.Dequeue(); double bestDist = best.realCost; #if DEBUG_PATHFINDER_LOGDEBUG encountered.Append("Node ").Append(best.Number).Append(" ").Append(best).AppendLine(); nodes.Append("Node ").Append(best.Number).AppendLine(); #endif //If this is the end, stop, show the path, and return it. if (best.Equals(end)) { ReconstructPath(pathStoreLoc, end); ShowPath(pathStoreLoc); #if DEBUG_PATHFINDER_LOGDEBUG encountered.Append("Finished!\n\nFinal dist: ") .Append(best.realCost).AppendLine(); Debug.Log(encountered); Debug.Log(nodes); #endif return best.realCost; } best.Visited = true; //string updateString = "updating: "; foreach (Edge e in best.getEdges()) { Node other = e.getNode(); //We already visited this node, move along, if (other.Visited) continue; //Tentative distance. double testDist = e.getWeight() + bestDist; //If the other node isn't in the priority queue, add it. if (!nodeList.Contains(other)) { other.CameFrom = best; other.realCost = testDist; other.heuristicCost = Heuristic(other, end); nodeList.Enqueue(other, other.realCost + other.heuristicCost); #if DEBUG_PATHFINDER_LOGDEBUG encountered.Append(" added ").Append(other.Number) .Append(", total estimated cost ") .Append(other.realCost + other.heuristicCost) .AppendLine(); #endif continue; } //If the other node was a bad path, and this one's better, replace it. else if (other.realCost > testDist) { other.CameFrom = best; other.realCost = testDist; nodeList.Update(other, other.realCost + other.heuristicCost); #if DEBUG_PATHFINDER_LOGDEBUG encountered.Append(" updated ").Append(other.Number) .Append(", total new estimated cost ") .Append(other.realCost + other.heuristicCost) .AppendLine(); #endif } } } #if DEBUG_PATHFINDER_LOGDEBUG encountered.Append("Failed!\n"); Debug.Log(encountered); Debug.Log(nodes); #endif return double.PositiveInfinity; }
static Brush ResolveNodeBrush(Node node, Brush baseBrush) { if ((node.state & (RenderState.Dragging | RenderState.Focus)) != 0) { return Brushes.DarkOrange; } else if ((node.state & RenderState.Hover) != 0) { return Brushes.LightSteelBlue; } else { return baseBrush; } }
/// <summary> /// Idea of this function: You give it a function that has captured local variables so you can /// run whatever you want on all nodes that are in range of a given node. /// </summary> /// <param name="listNodes">Look at all nodes in range of this node.</param> /// <param name="minDist">Minimum firing distance.</param> /// <param name="maxDist">Maximum firing distance.</param> /// <param name="funcToRun">What function we should run on the nodes in range.</param> public void runFuncOnAllNodesInRangeOfNode(Node n, int minDist, int maxDist, System.Action<Node> funcToRun) { runFuncOnAllNodesInRangeOfNode(funcToRun, n.getGridPos().x, n.getGridPos().y, minDist, maxDist); }
public void ShowPath(Queue<Node> Path) { Node[] PathCopy = Path.ToArray(); if (PathCopy.Length == 0) return; //If we were displaying a path, reset the colors. if (manualStartNode != null) manualStartNode.resetColor(); if (manualEndNode != null) manualEndNode.resetColor(); //Set the colors for the start and end nodes. manualStartNode = PathCopy[0]; manualEndNode = PathCopy[PathCopy.Length - 1]; manualEndNode.setColor(Node.endColor); manualStartNode.setColor(Node.startColor); //Recycle garbage path renderers if necessary. if (pathDrawer != null) { UnityEngine.Object.Destroy(pathDrawer); } pathDrawer = new GameObject("Path"); //Set up the line renderer for the path. // We loop back once, so have double nodes + 1. LineRenderer drawer = pathDrawer.AddComponent<LineRenderer>(); drawer.SetWidth(0.3f, 0.3f); drawer.SetColors(Color.green, Color.green); drawer.SetVertexCount(PathCopy.Length * 2 + 1); // Need this otherwise the width is wrong on first edge. drawer.SetPosition(0, PathCopy[0].getPos()); for (int i = 0; i < PathCopy.Length; i++) drawer.SetPosition(i + 1, PathCopy[i].getPos()); for (int i = PathCopy.Length - 1, j = PathCopy.Length + 1; i >= 0; i--, j++) drawer.SetPosition(j, PathCopy[i].getPos()); }
public static void PerformLayout(Graphics graphics, Node node) { if (node == null) return; var size = Measure(graphics, node); var position = node.Location; node.bounds = new RectangleF(position, size); var path = new GraphicsPath(FillMode.Winding); int connectorSize = (int)GraphConstants.ConnectorSize; int halfConnectorSize = (int)Math.Ceiling(connectorSize / 2.0f); var connectorOffset = (int)Math.Floor((GraphConstants.MinimumItemHeight - GraphConstants.ConnectorSize) / 2.0f); var left = position.X + halfConnectorSize; var top = position.Y; var right = position.X + size.Width - halfConnectorSize; var bottom = position.Y + size.Height; node.inputConnectors.Clear(); node.outputConnectors.Clear(); //node.connections.Clear(); var itemPosition = position; itemPosition.X += connectorSize + (int)GraphConstants.HorizontalSpacing; if (node.Collapsed) { foreach (var item in node.Items) { var inputConnector = item.Input; if (inputConnector != null && inputConnector.Enabled) { inputConnector.bounds = Rectangle.Empty; node.inputConnectors.Add(inputConnector); } var outputConnector = item.Output; if (outputConnector != null && outputConnector.Enabled) { outputConnector.bounds = Rectangle.Empty; node.outputConnectors.Add(outputConnector); } } var itemSize = PreRenderItem(graphics, node.titleItem, itemPosition); var realHeight = itemSize.Height - GraphConstants.TopHeight; var connectorY = itemPosition.Y + (int)Math.Ceiling(realHeight / 2.0f); node.inputBounds = new RectangleF(left - (GraphConstants.ConnectorSize / 2), connectorY, GraphConstants.ConnectorSize, GraphConstants.ConnectorSize); node.outputBounds = new RectangleF(right - (GraphConstants.ConnectorSize / 2), connectorY, GraphConstants.ConnectorSize, GraphConstants.ConnectorSize); } else { node.inputBounds = Rectangle.Empty; node.outputBounds = Rectangle.Empty; foreach (var item in EnumerateNodeItems(node)) { var itemSize = PreRenderItem(graphics, item, itemPosition); var realHeight = itemSize.Height; var inputConnector = item.Input; if (inputConnector != null && inputConnector.Enabled) { if (itemSize.IsEmpty) { inputConnector.bounds = Rectangle.Empty; } else { inputConnector.bounds = new RectangleF( left - (GraphConstants.ConnectorSize / 2), itemPosition.Y + connectorOffset, GraphConstants.ConnectorSize, GraphConstants.ConnectorSize); } node.inputConnectors.Add(inputConnector); } var outputConnector = item.Output; if (outputConnector != null && outputConnector.Enabled) { if (itemSize.IsEmpty) { outputConnector.bounds = Rectangle.Empty; } else { outputConnector.bounds = new RectangleF(right - (GraphConstants.ConnectorSize / 2), itemPosition.Y + realHeight - (connectorOffset + GraphConstants.ConnectorSize), GraphConstants.ConnectorSize, GraphConstants.ConnectorSize); } node.outputConnectors.Add(outputConnector); } itemPosition.Y += itemSize.Height + GraphConstants.ItemSpacing; } } node.itemsBounds = new RectangleF(left, top, right - left, bottom - top); }
/// <summary> /// Fills all nodes in area and connects edges as necessesary. /// Does not have stack overflow problems, but may create a graph /// that isn't connected all the way through. /// </summary> private void fillAll() { for (int y = 0; y < numYNodes; y++) { for (int x = 0; x < numXNodes; x++) { IntVec2 arrPos = new IntVec2(x, y); Vector2 newPosV2 = ArrPosToWorldSpace(arrPos); #if DEBUG_PATHFINDER_UPDATELOOP if (!Physics2D.OverlapCircle(newPosV2, radii, LAYER_FILTER_MASK)) #endif { nodeArr[y][x] = new Node(transform.gameObject, nodeImg, newPosV2, arrPos, Node.randWalkState(), radii * 2, numValidNodes++); //add up-left edge (inverse y) if (allowedPaths > Paths.quadDir) { if (x - 1 >= 0 && y - 1 >= 0 && nodeArr[y - 1][x - 1] != null && isOkayToFloodDiag(arrPos, IntVec2.down, IntVec2.left)) nodeArr[y][x].addBidirEdge(nodeArr[y - 1][x - 1], sqrt2); //add up-right edge (inverse y) if (x + 1 < numXNodes && y - 1 >= 0 && nodeArr[y - 1][x + 1] != null && isOkayToFloodDiag(arrPos, IntVec2.down, IntVec2.right)) nodeArr[y][x].addBidirEdge(nodeArr[y - 1][x + 1], sqrt2); } //add up edge if (y - 1 >= 0 && nodeArr[y - 1][x] != null && isOkayToFloodUDLR(arrPos, IntVec2.down, (Vector2)IntVec2.left)) nodeArr[y][x].addBidirEdge(nodeArr[y - 1][x], 1); //add left edge if (x - 1 >= 0 && nodeArr[y][x - 1] != null && isOkayToFloodUDLR(arrPos, IntVec2.left, (Vector2)IntVec2.up)) nodeArr[y][x].addBidirEdge(nodeArr[y][x - 1], 1); } } } }
static IEnumerable<NodeItem> EnumerateNodeItems(Node node) { if (node == null) yield break; yield return node.titleItem; if (node.Collapsed) yield break; foreach (var item in node.Items) yield return item; }
public void initializeWithArray(Vector2 lowLeftBound, Vector2 upRightBound, Node.SquareType[][] terrainArr) { lowerLeftBound = lowLeftBound; upperRightBound = upRightBound; numXNodes = terrainArr[0].Length; numYNodes = terrainArr.Length; // Determine correct node density float xDist = lowerLeftBound.x - upperRightBound.x; nodeDensity = numXNodes / xDist; // Magic number allows for proper drawing of nodes. radii = 0.75f / nodeDensity; numValidNodes = 0; // Initialize the node array. Note the inverted y, normal x setup. nodeArr = new Node[numYNodes][]; for (int y = 0; y < numYNodes; y++) { nodeArr[y] = new Node[numXNodes]; for (int x = 0; x < numXNodes; x++) { IntVec2 arrPos = new IntVec2(x, y); Vector2 newPosV2 = ArrPosToWorldSpace(arrPos); nodeArr[y][x] = new Node(transform.gameObject, nodeImg, newPosV2, arrPos, terrainArr[y][x], radii * 2, numValidNodes++); //add up-left edge (inverse y) if (allowedPaths > Paths.quadDir) { if (x - 1 >= 0 && y - 1 >= 0 && isOkayToFloodDiag(arrPos, IntVec2.down, IntVec2.left)) nodeArr[y][x].addBidirEdge(nodeArr[y - 1][x - 1], sqrt2); //add up-right edge (inverse y) if (x + 1 < numXNodes && y - 1 >= 0 && isOkayToFloodDiag(arrPos, IntVec2.down, IntVec2.right)) nodeArr[y][x].addBidirEdge(nodeArr[y - 1][x + 1], sqrt2); } //add up edge if (y - 1 >= 0 && isOkayToFloodUDLR(arrPos, IntVec2.down, (Vector2)IntVec2.left)) nodeArr[y][x].addBidirEdge(nodeArr[y - 1][x], 1); //add left edge if (x - 1 >= 0 && isOkayToFloodUDLR(arrPos, IntVec2.left, (Vector2)IntVec2.up)) nodeArr[y][x].addBidirEdge(nodeArr[y][x - 1], 1); } } isInitialized = true; }
public static SizeF Measure(Graphics context, Node node) { if (node == null) return SizeF.Empty; SizeF size = Size.Empty; size.Height = //(int)NodeConstants.TopHeight + (int)GraphConstants.BottomHeight; foreach (var item in EnumerateNodeItems(node)) { var itemSize = item.Measure(context); size.Width = Math.Max(size.Width, itemSize.Width); size.Height += GraphConstants.ItemSpacing + itemSize.Height; } if (node.Collapsed) size.Height -= GraphConstants.ItemSpacing; size.Width += GraphConstants.NodeExtraWidth; return size; }
public void AddNeighbor(Node<TNode> node) { if (node != null) mNeighbors.Add(node); }