protected override float h_func(ref NavGraph para_graph, ref NavNode para_nodeID, ref NavNode para_goalNodeID) { WorldNode wN1 = (WorldNode) para_nodeID; WorldNode wN2 = (WorldNode) para_goalNodeID; float retHVal = UnityEngine.Vector3.Distance(wN1.getWorldPt(),wN2.getWorldPt()); return retHVal; }
public bool addNode(NavNode para_nwNode) { bool successFlag = false; if( ! vertices.ContainsKey(para_nwNode.getNodeID())) { vertices.Add(para_nwNode.getNodeID(),para_nwNode); successFlag = true; } return successFlag; }
public void SetNextNode() { if ( Destination != null && Destination.Count > 0) { NextNode = destination.Dequeue(); return; } if (NextNode.type == NavNode.NodeType.Door) doorsVisited.Add(NextNode); SetNextDestination(); }
public override void OnInspectorGUI() { DrawDefaultInspector(); NavNode graph = (NavNode)target; if (GUILayout.Button("Insert Node")) { NavNode node = graph.InsertNode(); Selection.activeGameObject = node.gameObject; SceneView.lastActiveSceneView.FrameSelected(); } }
public SubMove(AgentBase agentBase, NavNode startingNode, object agentStartingData, NavNode destinationNode, Vector3Int dir, bool moveCritical = true, SubMove criticalFor = null, SubMove reliesOn = null, int subMovePriority = 0) { this.agentStartingData = agentStartingData; this.subMovePriority = subMovePriority; this.criticalFor = criticalFor; SetReliesOn(reliesOn); finishedExecuting = false; //todo change this language to finishedAnimation or something more clear, inconsistent use of the word executing. this.moveCritical = moveCritical; this.dir = dir; //uh, we can just calculate this from destination-starting? I wont jic teleportation becomes like, a move? so we would pass in the previous ... direction entering the teleporter? this.agent = agentBase; this.startingNode = startingNode; this.destinationNode = destinationNode; }
GameObject GenerateCard(int n) { GameObject newCard = Object.Instantiate(baseHex, transform); NavNode newNode = newCard.GetComponent <NavNode>(); int ring = n % nParamValues; int position = (n / nParamValues) % nParamValues; int color = ((n / nParamValues) / nParamValues) % nParamValues; int shape = (((n / nParamValues) / nParamValues) / nParamValues) % nParamValues; newNode.Configure(ring, position, color, shape); return(newCard); }
private IEnumerator LinkNodes(NavNode start) { foreach (NavNode node in nodes) { if (!node.Equals(start) && !start.links.ContainsKey(node) && CheckNeighbor(start.pos, node.pos)) { yield return(new WaitForSeconds(0.2f)); start.Link(node); yield return(LinkNodes(node)); } } }
void OnDrawGizmosSelected() { // Draw bounds Bounds bounds = globalBounds; Gizmos.color = Color.yellow; Gizmos.DrawWireCube(bounds.center, bounds.size); // Draw nodes if (nodes != null) { Gizmos.color = Color.green; foreach (NavNode c in nodes) { Gizmos.DrawSphere(c.location, 0.1f); // Draw connections foreach (int n in c.neighbours) { if (nodes[n].id < c.id) { Gizmos.DrawLine(nodes[n].location, c.location); } } } } // DRAW TEST Gizmos.color = Color.green; Gizmos.DrawCube(testStart, Vector3.one * 0.5f); NavNode a = GetClosestNode(testStart); Gizmos.DrawSphere(a.location, 0.5f); Gizmos.color = Color.red; Gizmos.DrawCube(testEnd, Vector3.one * 0.5f); NavNode b = GetClosestNode(testEnd); Gizmos.DrawSphere(b.location, 0.5f); Gizmos.color = Color.black; if (testPath != null) { foreach (NavNode node in testPath) { Gizmos.DrawSphere(node.location, 0.25f); } } }
private bool CheckNeighbor(Vector2 pos1, Vector2 pos2) { Vector2 center = (pos1 + pos2) / 2f; NavNode closest = nodes.OrderBy(i => (center - i.pos).magnitude).FirstOrDefault(); if (closest.pos.Equals(pos1) || closest.pos.Equals(pos2)) { GameObject edge = Instantiate(debugEdge, center, Quaternion.identity, transform); LineRenderer lr = edge.GetComponent <LineRenderer>(); lr.SetPositions(new Vector3[] { pos1, pos2 }); return(true); } return(false); }
bool CheckCluster(NavNode node1, NavNode node2, NavNode node3) { int[] props1 = node1.GetProperties(); int[] props2 = node2.GetProperties(); int[] props3 = node3.GetProperties(); for (int i = 0; i < nParams; i++) { if ((props1[i] + props2[i] + props3[i]) % nParamValues != 0) { return(false); } } return(true); }
public void ExpandNode(NavNode n) { RemoveFromFringe(n); if (DynamicWeight) { HeuristicWeight += DynamicWeightStep; } // loop adjacent Dictionary <NavNode, GRID_DIRECTION> neighbors = g_Grid.GetNeighborNodes(n); foreach (NavNode neighbor in neighbors.Keys) { if (neighbor.IsWalkable()) { if (!g_gVal.ContainsKey(neighbor)) { g_gVal.Add(neighbor, float.MaxValue); } float val = g_gVal[n] + ComputeNodeCost(n, neighbor, neighbors[neighbor]); if (g_gVal[neighbor] > val) { g_gVal[neighbor] = val; g_Parents.Remove(neighbor); g_Parents.Add(neighbor, n); if (!g_ClosedList.Contains(neighbor)) { if (g_OpenList.Contains(neighbor)) { RemoveFromFringe(neighbor); } g_OpenList.Add(neighbor); if (UseBeaconHeuristic) { if (UseBeaconHeuristic && g_Fringe.Count > BeaconFringeLimit) { NavNode last = g_Fringe.Values[g_Fringe.Count - 1]; g_gVal.Remove(last); g_Parents.Remove(last); g_OpenList.RemoveWhere(i => i.Equals(last)); g_Fringe.RemoveAt(g_Fringe.Count - 1); } } g_Fringe.Add(val + ComputeNodeHeuristic(neighbor), neighbor); } } } } }
public void Generate(Map map, NavNode start) { Reset(); BrushGraph(start, wallPositions, map.trunkWidth + map.wallWidth, true); BrushGraph(start, floorPositions, map.trunkWidth + map.wallWidth / 2, true); BrushGraph(start, wallPositions, map.trunkWidth, false); ContourPositions(wallContours, wallPositions); MapContours(walls, wallContours, map.wallTiles); MapPositions(floor, floorPositions, map.floorTile); MapShadows(decor, wallContours, map.shadowTiles); }
/// <summary> /// Coroutine to search for the destination, simply waiting until destination is found. /// </summary> private IEnumerator FindPathToDestination(NavNode final) { _pathfinder.Search(_player.CurrentNode, final); //Wait for pathfinder to finish its search. while (_pathfinder.Running) { yield return(null); } if (_pathfinder.PathStatus == PathStatus.success) { _moveChainCoroutine = StartCoroutine(MoveToDestination(_pathfinder.GetPath())); } }
public List <Vector2Int> UnwrapPath(NavNode node, out float distance) { distance = 0.0f; List <Vector2Int> result = new List <Vector2Int>(); while (node != null) { distance += node.GScore; result.Add(node.Data); node = node.Parent; } return(result); }
void SetWalkable() { Vector2 grid_dim = mesh.GetGridDimentions(); int i = 0; for (int x = 0; x < grid_dim.x; x++) { for (int y = 0; y < grid_dim.y; y++) { NavNode n = mesh.GetNode(x, y); n.SetWalkable(!Physics2D.OverlapCircle(n.GetPosiotion(), node_size / 2, obsticle_mask)); } } }
public NavNode Graph(float width) { Vector2 startPos = Eval(0.0); Vector2 endPos = Eval(1.0); NavNode start = new NavNode(startPos); NavNode end = new NavNode(endPos); start.Link(end); GraphRec(width, start, end, 0.0, 1.0); return(start); }
/// <summary> /// calculates distance to root from every other node, must be called after changing the root /// </summary> /// <param name="root"></param> private void CalculateDistances(NavNode root) { //reset distances distancesFromRoot.Clear(); foreach (NavNode node in MapNodes) { distancesFromRoot.Add(node, float.MaxValue); } //set up initial conditions for the search List <NavNode> visitedNodes = new List <NavNode>(); visitedNodes.Add(root); Stack <Edge> edgesToVisit = new Stack <Edge>(); distancesFromRoot[root] = 0; foreach (NavNode node in root.ConnectedNodes) { edgesToVisit.Push(new Edge(root, node)); } //begin calculation of distances while (edgesToVisit.Count > 0) { //take an edge off the stack Edge currentEdge = edgesToVisit.Pop(); //the current node is the one we just traveled to across the edge NavNode currentNode = currentEdge.to; //reduce the distance if the current route is shorter distancesFromRoot[currentNode] = Mathf.Min( distancesFromRoot[currentNode], //this is the length of the current shortest path back to root from the current node (or it's float.MaxValue) distancesFromRoot[currentEdge.from] + currentEdge.length); //but it might be faster to travel through the route we just took instead //if we haven't visited that node yet, add its connections as edges to the stack if (!visitedNodes.Contains(currentNode)) { foreach (NavNode node in currentNode.ConnectedNodes) { edgesToVisit.Push(new Edge(currentNode, node)); } visitedNodes.Add(currentNode); } } }
public void addConnectionSymmetric(NavNode other, int weight, Graph graph) { switch (graph) { case Graph.Complete: allCons.Add(new NavConnection(other, weight)); other.allCons.Add(new NavConnection(this, weight)); break; case Graph.Corners: cornerCons.Add(new NavConnection(other, weight)); other.cornerCons.Add(new NavConnection(this, weight)); break; } }
void generateNodes() { int id = 0; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { var tempNode = new NavNode(id++, i, j); tempNode.setPosition(resolution * (i + 0.5), resolution * (j + 0.5)); nodes.Add(tempNode); } } base.init(); }
/// <summary> /// sets closestNode to be the closest node to this gameobject's transform /// </summary> private void CalculateNearestNavNode() { float shortestDistance = float.MaxValue; foreach (NavNode node in pathFinder.MapNodes) { float distance = Vector3.SqrMagnitude(node.transform.position - transform.position); if (distance < shortestDistance) { closestNode = node; shortestDistance = distance; } } }
/// <summary> /// Calculates the distance cost between to nodes. /// </summary> /// <param name="from">The node to start from.</param> /// <param name="to">The node to end at.</param> /// <returns>The distance cost value.</returns> static int GetDistance(NavNode from, NavNode to) { var connection = new Vector2Int( Mathf.Abs(to.Position.x - from.Position.x), Mathf.Abs(to.Position.y - from.Position.y)); var isLargerX = Mathf.Abs(connection.x) > Mathf.Abs(connection.y); var larger = isLargerX ? connection.x : connection.y; var smaller = isLargerX ? connection.y : connection.x; var distance = (larger - smaller) * 10 + smaller * 14; return(distance); }
void FollowCourse() { ship.Engine.MoveToward(destination.Position); if (Vector3.Distance(transform.position, destination.Position) <= REACHED_THRESHOLD) { if (destination.IsLast) { ship.Remove(); } else { destination = destination.Next; } } }
/// <summary> /// Create a NPC. /// AGXNASK distribution has npAgent move following a Path. /// </summary> /// <param name="theStage"> the world</param> /// <param name="label"> name of </param> /// <param name="pos"> initial position </param> /// <param name="orientAxis"> initial rotation axis</param> /// <param name="radians"> initial rotation</param> /// <param name="meshFile"> Direct X *.x Model in Contents directory </param> public NPAgent(Stage theStage, string label, Vector3 pos, Vector3 orientAxis, float radians, string meshFile) : base(theStage, label, pos, orientAxis, radians, meshFile) { // change names for on-screen display of current camera first.Name = "npFirst"; follow.Name = "npFollow"; above.Name = "npAbove"; // IsCollidable = true; // have NPAgent test collisions // path is built to work on specific terrain path = new Path(stage, makePath(), Path.PathType.REVERSE); // continuous search path stage.Components.Add(path); nextGoal = path.NextNode; // get first path goal agentObject.turnToFace(nextGoal.Translation); // orient towards the first path goal }
static NavNode getLowestOpen(List <NavNode> openList) { float lowest = float.MaxValue; NavNode lNode = null; for (int i = 0; i < openList.Count; i++) { if (openList[i].pInfo.getCost() < lowest) { lowest = openList[i].pInfo.getCost(); lNode = openList[i]; } } return(lNode); }
public void push(NavNode myNode) { size++; array[size] = myNode; // select min movement or max f sorting if (ai) { aiSiftUp(size); } else { siftUp(size); } }
protected override float g_func(ref NavGraph para_graph, ref NavNode para_node1, ref NavNode para_node2) { NavEdge reqEdge = para_graph.getEdge(para_node1.getNodeID(),para_node2.getNodeID()); float retGVal = 0; if(reqEdge == null) { retGVal = float.PositiveInfinity; } else { retGVal = reqEdge.getCost(); } return retGVal; }
public void CurrentNeighbours_ReturnsLowestWeightedNeighbour() { var lowestWeightNode = new NavNode { Weight = 1 }; var higherWeightNode = new NavNode { Weight = lowestWeightNode.Weight + 1 }; var currentNode = new NavNode { Position = new Vector2(1.0f, 5.0f), NeighbourRefs = new [] { lowestWeightNode, higherWeightNode } }; Assert.AreSame(lowestWeightNode, new LowestCostBestFitHeuristic().GetBestNode(currentNode, null, null)); }
public bool RemoveFromFringe(NavNode n) { if (g_OpenList.Contains(n)) { for (int q = 0; q < g_Fringe.Count; q++) { if (g_Fringe.Values[q].Equals(n)) { g_OpenList.Remove(n); g_Fringe.RemoveAt(q); return(true); } } } return(false); }
public void GenerateNavRegionsFromNodes_CreatesExpectedNumberOfRegionsForClashingPoints() { const int neighbourCount = 4; const int singleNodes = 30; const int expectedRegionCount = 5; var nodesToAllocate = new List <NavNode>(); var neighbourNodes = new List <NavNode>(neighbourCount); NavNode priorNode = null; for (int j = 0; j < expectedRegionCount; j++) { for (int i = 0; i < singleNodes; i++) { var newNode = new NavNode(); for (int k = 0; k < neighbourCount - 1; k++) { var newNeighbour = new NavNode(); neighbourNodes.Add(newNeighbour); } if (priorNode != null) { var updatedPriorNeighbours = priorNode.NeighbourRefs.ToList(); updatedPriorNeighbours.Add(newNode); priorNode.NeighbourRefs = updatedPriorNeighbours.ToArray(); neighbourNodes.Add(priorNode); } newNode.NeighbourRefs = neighbourNodes.ToArray(); nodesToAllocate.Add(newNode); foreach (var neighbourNode in neighbourNodes) { nodesToAllocate.Add(neighbourNode); } neighbourNodes.Clear(); priorNode = newNode; } } Assert.AreEqual(1, NavRegionGenerationFunctions.GenerateNavRegionsFromNodes(nodesToAllocate, singleNodes * neighbourCount).Count); }
void OnDrawGizmos() { if (grid != null) { NavNode playerNode = GetNodeFromWorld(PlayerController.playerTrans.position); foreach (NavNode n in grid) { Gizmos.color = (n.walkable) ? new Color(1, 1, 1, 0.2f) : Color.red; if (playerNode == n) { Gizmos.color = Color.cyan; } Gizmos.DrawCube(n.worldPosition, Vector3.one * (nodeDiameter - .05f)); } } }
public void SetStartEnd(GameObject marker) { if (!startDefined) { myStart = marker.GetComponent <NavNode>(); startDefined = true; uiController.NavigationPanelControl(1); } else { myEnd = marker.GetComponent <NavNode>(); startDefined = false; StartPathCalculation(); uiController.NavigationPanelControl(2); } }
/* Creates the vertices for this map. */ public IEnumerator Initialize(Vector3 max, Vector3 min) { for (float x = min.x; x < max.x; x += boxSize) { for (float z = min.y; z < max.z; z += boxSize) { NavNode node = new NavNode(); node.id = nextId; nextId++; node.pos = new Vector3(x, 0f, z); node.initialized = false; } } yield return(new WaitForSeconds(0f)); }
public void NullDestination_ReturnsNull() { var currentNode = new NavNode { Position = new Vector2(10.0f, 1.0f), NeighbourRefs = new[] { new NavNode { Position = new Vector2(12.0f, 1.0f) } } }; Assert.IsNull(new ClosestNodeBestFitHeuristic().GetBestNode(currentNode, null, null)); }
public override bool Equals(object obj) { if (obj == null) { return(false); } if (this.GetType() != obj.GetType()) { return(false); } NavNode other = (NavNode)obj; return(Data == other.Data); }
public async Task <bool> AddAsync(NavNodeDto dto) { try { using (var dbContext = _dbContextScopeFactory.Create()) { var entity = NavNode.Create(dto); _navNodeRepository.Add(entity); await dbContext.SaveChangesAsync(); return(true); } } catch (Exception ex) { } return(false); }
/// <summary> /// Calculate the distance between a node n /// and its neighbor m. It's either /// 150 or 150 * \sqrt{2} /// </summary> /// <param name="n">a node n</param> /// <param name="m">neighbor of m</param> /// <returns>the distance between 2 nodes</returns> public double CalculateDistanceFromSource(NavNode n, NavNode m) { // first we convert their actual location // to node on graph. Then we truncate // all the decimal points. So it returns // a pair of (x, z) -> (512, 512) int xN = (int)(n.Translation.X / 150); int zN = (int)(n.Translation.Z / 150); int xM = (int)(m.Translation.X / 150); int zM = (int)(m.Translation.Z / 150); // next we find their location int temp = Math.Abs(xN - xM) + Math.Abs(zN - zM); // this is corner if (temp == 2) return stage.Spacing * Math.Sqrt(2); else return stage.Spacing; }
public bool addNode(NavNode para_nwNode) { return vertices.addNode(para_nwNode); }
public void Update(double elapsedTime) { _nodeUI.ForEach(x => x.Update(elapsedTime, _input.Mouse.Position)); if (_input.Mouse.LeftPressed) { NodeUI node = _nodeUI.Find(x => x.HasFocus()); if (node != null) { if (_start == null) { _start = node.Node; } else if (_end == null) { _end = node.Node; _astar.FindPath(_start, _end); _astar.Path.Reverse(); } else { // Time to reset. } } } }
/// <summary> /// ---------------- /// - A* Algorithm - /// ---------------- /// /// OPEN = priority queue contain START /// CLOSED = empty set /// /// while lowest rank in OPEN is not the GOAL: /// current = remove lowest rank item from OPEN /// add current to CLOSED /// /// for neighbors of current /// cost = g(current) + movement_cost(current, neighbor) /// /// if neighbor in OPEN and cost less than g(neighbor) /// remove neighbor from OPEN, because new path is better /// /// if neighbor in CLOSED and cost less than g(neighbor) /// remove neighbor from CLOSED /// /// if neighbor not in OPEN and neighbor not in CLOSED /// set g(neighbor) to cost /// add neighbor to OPEN /// set priority queue rank to g(neighbor) + h(neighbor) /// set neighbor's parent to current /// /// /// reconstruct reverse path from goal to start /// by following parent pointers /// /// </summary> /// <param name="startPostion">start</param> /// <param name="goalPosition">destination</param> /// <param name="nodeType">color of node</param> /// <returns></returns> private List<NavNode> MakeAStarPath(Vector3 startPostion, Vector3 goalPosition, NavNode.NavNodeEnum nodeType) { /** * A* implementation * Summary: * 1) Add the starting node to the open set * 2) Repeat the following: * a) Look for the lowest F cost on the open set. * b) Move it to the closed set * c) For each of the 8 adjacency node to the current node: * + If it is NOT walkable or if it is on the CLOSED SET, just ignore it. * + Otherwise: * - If it is NOT on the OPEN SET, add it to the OPEN SET. Make the "current node" as * parent of this adjacency node. Record F, G, H for this node. * - If it is on the OPEN SET already, check to see if this path to that square is * better using G cost as the measure. A lower G means that this is a better path. * If so, change the parent of the node to the "current node", and recalculate * the G and F cost of the node. * d) Stop when we: * + Add the goal node to the closed set, in which case the path has been found. * + Fail to find the goal node, and the open set is empty. In this case, there is NO path. */ // spacing between node on map (= 150) int spacing = stage.Terrain.Spacing; /** * A* path * this is our final path */ List<NavNode> path = new List<NavNode>(); /** * The starting point */ NavNode start = new NavNode(startPostion); start.DistanceFromSource = 0.0; start.DistanceToGoal = 0.0; start.Distance = 0.0; start.Parent = null; /** * The goal */ NavNode goal = new NavNode(goalPosition); goal.DistanceFromSource = 0.0; goal.DistanceToGoal = 0.0; goal.Distance = 0.0; goal.Parent = null; // open set PriorityQueue<NavNode> openSet = new PriorityQueue<NavNode>(); // close set PriorityQueue<NavNode> closedSet = new PriorityQueue<NavNode>(); // add starting point to open set (part 1) openSet.Add(start); while (!openSet.Empty) { // get the current node with lowest cost F and remove it from open set NavNode current = openSet.Pop(); // add current to close set closedSet.Add(current); // if it's equal to our goal, we're done (part d) if (current.IsSameLocation(goal)) { while (current.Parent != null) { path.Add(current); current.Navigatable = nodeType; current = current.Parent; } path.Reverse(); return path; } else { // for each of the 8 adjacency neighbors // NOTE: the neighbor list already removed un-walkable nodes List<NavNode> neighbors = GetNeighbors(current.Translation); foreach (NavNode n in neighbors) { // if it's on the closed set, just ignore it if (IsNodeIn(n, closedSet)) { continue; } else { if (!IsNodeIn(n, openSet)) { // make the "current node" as parent of this neighbor n.Parent = current; // record new F, G, H n.DistanceFromSource = current.DistanceFromSource + CalculateDistanceFromSource(current, n); n.DistanceToGoal = CalculateHeuristicDinstanceToGoal(n, goal); n.Distance = n.DistanceFromSource + n.DistanceToGoal; // add this neighbor to the OPEN SET openSet.Add(n); } else { // it's already on the OPEN SET double costFromThisPathToN = current.DistanceFromSource + CalculateDistanceFromSource(current, n); // we have a better path, going from "current node" if (costFromThisPathToN < n.DistanceFromSource) { // recalculate G and F for this neighbor n.Parent = current; n.DistanceFromSource = costFromThisPathToN; n.Distance = n.DistanceFromSource + n.DistanceToGoal; } } } } } } return path; }
private void HandleTreasureMode() { if (treasurePathQueue.Count == 0) { // switch mode mode = ModeEnum.EXPLORING; npAgentGameMode = Stage.GameMode.NP_AGENT_EXPLORING; // resume to previous exploring path if any if (previousPath != null && !previousPath.Done) { currentPath = previousPath; // nextGoal = currentPath.NextNode; // agentObject.TurnToFace(nextGoal.Translation); } else { HandleExploringMode(); } } else { // get another path from treasure path queue currentPath = treasurePathQueue.Dequeue(); // add path to stage two show trace stage.Components.Add(currentPath); // get first path goal nextGoal = currentPath.NextNode; // orient towards the first path goal agentObject.TurnToFace(nextGoal.Translation); } }
/// <summary> /// Here we allow switching from regular path to treasure path if only if /// the treasure path is not done, otherwise it will do nothing (disable) /// </summary> private void ChangeToTreasurePath(int idx) { AddNewTreasurePath(idx); // save the previous path if any if (mode == ModeEnum.EXPLORING) { if (!currentPath.Done) { previousPath = currentPath; } } // update the mode mode = ModeEnum.TREASURE_HUNTING; // set new path currentPath = treasurePathQueue.Dequeue(); // add path to stage stage.Components.Add(currentPath); // get the first target nextGoal = currentPath.NextNode; // orient towards the first path goal agentObject.TurnToFace(nextGoal.Translation); }
// Finds a path between the start node and the destination node using A* pathfinding algorithm public List<NavNode> AStarSearch(NavNode start, NavNode destination){ // Initialize the necessary lists and variables for A* pathfinding List<NavNode> all = new List<NavNode>(); all.Add(start); List<NavNode> closed = new List<NavNode>(); List<NavNode> open = new List<NavNode>(all); List<NavNode> path = new List<NavNode>(); //float totalCost = 0; //float currentBest = 0; while (open[0] != destination){ NavNode lowest = open[0]; // Find the node with the lowest value in open int openCount = open.Count; for (int i = 0; i < openCount; i++){ NavNode currentNode = open[i]; if (currentNode.GetCostToHere() < lowest.GetCostToHere()){ lowest = currentNode; } } // Remove the current lowest from open and add it to the closed since it is being visited open.Remove (lowest); closed.Add (lowest); // Iterate through the neighbors of the selected node int lowestNeighborCount = lowest.GetNeighborNodes().Count; for (int i = 0; i < lowestNeighborCount; i++){ NavNode currentNeighbor = lowest.GetNeighborNodes()[i]; // Calculate the cost as the distance between the current node and the current neighbor float cost = lowest.GetCostToHere() + Vector3.Distance(lowest.transform.position, currentNeighbor.transform.position); if (open.Contains(currentNeighbor) && cost < currentNeighbor.GetCostToHere()) { open.Remove(currentNeighbor); } if (closed.Contains(currentNeighbor) && cost < currentNeighbor.GetCostToHere()) { closed.Remove(currentNeighbor); } if (!open.Contains(currentNeighbor) && !closed.Contains(currentNeighbor)) { //currentBest = cost; // If the open list is empty, add the current neighbor to the open list if (open.Count == 0){ open.Add(currentNeighbor); } // Otherwise, place the node in the open list at the appropriate position according to its cost else { bool addedToOpen = false; int count = open.Count; for (int j = 0; j < count; j++){ if (cost < open[j].GetCostToHere()){ open.Insert(j, currentNeighbor); addedToOpen = true; break; } } if (!addedToOpen){ open.Insert (open.Count, currentNeighbor); } } // Set the cost and parent of the current neighbor currentNeighbor.SetCostToHere(cost); currentNeighbor.SetParentNode(lowest); } } } // Once finished, determine what the path is by looking at the parent nodes and insert them into the path in the proper order NavNode node = destination; while (node.GetParentNode() != start){ path.Insert(0, node); node = node.GetParentNode(); } path.Insert(0, node); return path; }
private int snapDistance = 20; // this should be a function of step and stepSize #endregion Fields #region Constructors /// <summary> /// Create a NPC. /// AGXNASK distribution has npAgent move following a Path. /// </summary> /// <param name="theStage"> the world</param> /// <param name="label"> name of </param> /// <param name="pos"> initial position </param> /// <param name="orientAxis"> initial rotation axis</param> /// <param name="radians"> initial rotation</param> /// <param name="meshFile"> Direct X *.x Model in Contents directory </param> public NPAgent(Stage theStage, string label, Vector3 pos, Vector3 orientAxis, float radians, string meshFile) : base(theStage, label, pos, orientAxis, radians, meshFile) { // change names for on-screen display of current camera first.Name = "npFirst"; follow.Name = "npFollow"; above.Name = "npAbove"; // path is built to work on specific terrain, make from int[x,z] array pathNode path = new Path(stage, pathNode, Path.PathType.LOOP); // continuous search path stage.Components.Add(path); nextGoal = path.NextNode; // get first path goal agentObject.turnToFace(nextGoal.Translation); // orient towards the first path goal // set snapDistance to be a little larger than step * stepSize snapDistance = (int) (1.5 * (agentObject.Step * agentObject.StepSize)); }
/// <summary> /// Simple path following. If within "snap distance" of a the nextGoal (a NavNode) /// move to the NavNode, get a new nextGoal, turnToFace() that goal. Otherwise /// continue making steps towards the nextGoal. /// </summary> public override void Update(GameTime gameTime) { KeyboardState keyboardState = Keyboard.GetState(); if ((keyboardState.IsKeyDown(Keys.N) && !oldKeyboardState.IsKeyDown(Keys.N)) && currentState == UpdateState.PATH_FOLLOWING) currentState = UpdateState.TREASURE_GOAL; // toggle NPAgent update state. float distance; switch(currentState) { case UpdateState.PATH_FOLLOWING : agentObject.turnToFace(nextGoal.Translation); // adjust to face nextGoal every move // See if at or close to nextGoal, distance measured in 2D xz plane distance = Vector3.Distance( new Vector3(nextGoal.Translation.X, 0, nextGoal.Translation.Z), new Vector3(agentObject.Translation.X, 0, agentObject.Translation.Z)); stage.setInfo(15, stage.agentLocation(this)); stage.setInfo(16, string.Format(" nextGoal ({0:f0}, {1:f0}, {2:f0}) distance to next goal = {3,5:f2})", nextGoal.Translation.X/stage.Spacing, nextGoal.Translation.Y, nextGoal.Translation.Z/stage.Spacing, distance) ); if (distance <= snapDistance) { // snap to nextGoal and orient toward the new nextGoal nextGoal = path.NextNode; // agentObject.turnToFace(nextGoal.Translation); } oldKeyboardState = keyboardState; // Update saved state. base.Update(gameTime); // Agent's Update(); break; case UpdateState.TREASURE_GOAL : agentObject.turnToFace(new Vector3(67050,100,67950)); // adjust to face nextGoal every move // See if at or close to nextGoal, distance measured in 2D xz plane distance = Vector3.Distance( new Vector3(67050,0,67950), new Vector3(agentObject.Translation.X, 0, agentObject.Translation.Z)); stage.setInfo(15, stage.agentLocation(this)); //stage.setInfo(16, // string.Format(" nextGoal ({0:f0}, {1:f0}, {2:f0}) distance to next goal = {3,5:f2})", // nextGoal.Translation.X/stage.Spacing, nextGoal.Translation.Y, nextGoal.Translation.Z/stage.Spacing, distance) ); if (distance <= 300) { // snap to nextGoal and orient toward the new nextGoal //nextGoal = path.NextNode; currentState = UpdateState.PATH_FOLLOWING; // agentObject.turnToFace(nextGoal.Translation); } oldKeyboardState = keyboardState; // Update saved state. base.Update(gameTime); // Agent's Update(); break; } }
public void SetParentNode(NavNode newParent){ m_parentNode = newParent; }
public List<NavNode> getChildNodesAtHopDistance(NavNode para_sourceNode, int para_distanceFromSrc, HashSet<int> para_untraversibleTypes, HashSet<int> para_untraversibleNodes) { // Uses modified Breadth First Search. List<NavNode> retList = new List<NavNode>(); int depthLevel = 0; List<int> candidateNodeIDs = new List<int>(); List<int> nwCandidateNodeIDs = new List<int>(); HashSet<int> seenNodes = new HashSet<int>(); candidateNodeIDs.Add(para_sourceNode.getNodeID()); if(para_distanceFromSrc > 0) { do { for(int i=0; i<candidateNodeIDs.Count; i++) { int cNodeID = candidateNodeIDs[i]; if( ! seenNodes.Contains(cNodeID)) { seenNodes.Add(cNodeID); NavNode cNode = getNode(cNodeID); HashSet<int> cNodeNeighbours = cNode.getAllNeighbourIDs(); foreach(int neighbourID in cNodeNeighbours) { bool isValid = true; if(depthLevel == (para_distanceFromSrc-1)) { if(seenNodes.Contains(neighbourID)) { isValid = false; } } if(para_untraversibleNodes != null) { if(para_untraversibleNodes.Contains(neighbourID)) { isValid = false; } } if(para_untraversibleTypes != null) { if(para_untraversibleTypes.Contains(getNode(neighbourID).getNodeType())) { isValid = false; } } if(isValid) { nwCandidateNodeIDs.Add(neighbourID); } } } } candidateNodeIDs.Clear(); candidateNodeIDs = nwCandidateNodeIDs; nwCandidateNodeIDs = new List<int>(); depthLevel++; } while((depthLevel < para_distanceFromSrc)&&(candidateNodeIDs.Count > 0)); } for(int i=0; i<candidateNodeIDs.Count; i++) { retList.Add(getNode(candidateNodeIDs[i])); } return retList; }
/// <summary> /// Calculate the distance between a node n /// and its goal using Manhattan formula. /// We count the number squares vertically and /// horizontally to from n to the goal /// </summary> /// <param name="n">a node on graph</param> /// <param name="goal">a goal</param> /// <returns>their distance</returns> public double CalculateHeuristicDinstanceToGoal(NavNode n, NavNode goal) { // first we convert their actual location // to node on graph. Then we truncate // all the decimal points. So it returns // a pair of (x, z) -> (512, 512) int xN = (int)(n.Translation.X / 150); int zN = (int)(n.Translation.Z / 150); int xGoal = (int)(goal.Translation.X / 150); int zGoal = (int)(goal.Translation.Z / 150); // then we take the number squares times 150 return stage.Spacing * (Math.Abs(xN - xGoal) + Math.Abs(zN - zGoal)); }
private bool IsValidMove(NavNode[] grid, int ax, int ay, int bx, int by) { if(grid[bx + by * _map.Width]._cost == BlockerCost) return false; // Diagonal movement must NOT go past any blocker neighbors if(ax != bx && ay != by) { if( grid[ax + by * _map.Width]._cost == BlockerCost || grid[bx + ay * _map.Width]._cost == BlockerCost) return false; } return true; }
/// <summary> /// Get all neighbors of a node on map. /// There are 512 x 512 nodes /// and 8 possible neighbors for each node /// </summary> /// <param name="node">a position on map</param> /// <returns></returns> public List<NavNode> GetNeighbors(Vector3 node) { // initialize collection List<NavNode> neighbors = new List<NavNode>(); // convert to x, z coordinate to map to (512, 512) int x = (int)(node.X / 150); int z = (int)(node.Z / 150); int spacing = stage.Spacing; Terrain terrain = stage.Terrain; /* * 8 possible adjacent neighbors * ---------------------------------------------------- * | (x - 1, z - 1) | (x, z - 1) | (x + 1, z - 1) | * ---------------------------------------------------- * | (x - 1, z) | (x, z) | (x + 1, z) | * ---------------------------------------------------- * | (x - 1, z + 1) | (x, z + 1) | (x + 1, z + 1) | * ---------------------------------------------------- */ // left if (IsInRange(x - 1, z)) { Vector3 left = new Vector3((x - 1) * spacing, terrain.SurfaceHeight(x - 1, z), z * spacing); if (IsWalkable(left)) { NavNode n = new NavNode(left, NavNode.NavNodeEnum.A_STAR); neighbors.Add(n); } } // right if (IsInRange(x + 1, z)) { Vector3 right = new Vector3((x + 1) * spacing, terrain.SurfaceHeight(x + 1, z), z * spacing); if (IsWalkable(right)) { NavNode n = new NavNode(right, NavNode.NavNodeEnum.A_STAR); neighbors.Add(n); } } // up if (IsInRange(x, z - 1)) { Vector3 up = new Vector3(x * spacing, terrain.SurfaceHeight(x, z - 1), (z - 1) * spacing); if (IsWalkable(up)) { NavNode n = new NavNode(up, NavNode.NavNodeEnum.A_STAR); neighbors.Add(n); } } // down if (IsInRange(x, z + 1)) { Vector3 down = new Vector3(x * spacing, terrain.SurfaceHeight(x, z + 1), (z + 1) * spacing); if (IsWalkable(down)) { NavNode n = new NavNode(down, NavNode.NavNodeEnum.A_STAR); neighbors.Add(n); } } // upper left if (IsInRange(x - 1, z - 1)) { Vector3 upperLeft = new Vector3((x - 1) * spacing, terrain.SurfaceHeight(x - 1, z - 1), (z - 1) * spacing); if (IsWalkable(upperLeft)) { NavNode n = new NavNode(upperLeft, NavNode.NavNodeEnum.A_STAR); neighbors.Add(n); } } // upper right if (IsInRange(x + 1, z - 1)) { Vector3 upperRight = new Vector3((x + 1) * spacing, terrain.SurfaceHeight(x + 1, z - 1), (z - 1) * spacing); if (IsWalkable(upperRight)) { NavNode n = new NavNode(upperRight, NavNode.NavNodeEnum.A_STAR); neighbors.Add(n); } } // lower left if (IsInRange(x - 1, z + 1)) { Vector3 lowerLeft = new Vector3((x - 1) * spacing, terrain.SurfaceHeight(x - 1, z + 1), (z + 1) * spacing); if (IsWalkable(lowerLeft)) { NavNode n = new NavNode(lowerLeft, NavNode.NavNodeEnum.A_STAR); neighbors.Add(n); } } // lower Right if (IsInRange(x + 1, z + 1)) { Vector3 lowerRight = new Vector3((x + 1) * spacing, terrain.SurfaceHeight(x + 1, z + 1), (z + 1) * spacing); if (IsWalkable(lowerRight)) { NavNode n = new NavNode(lowerRight, NavNode.NavNodeEnum.A_STAR); neighbors.Add(n); } } return neighbors; }
public bool Rebuild(IEnumerable<Point> blockers) { NavNode[] newGrid = new NavNode[_map.Width * _map.Height]; PriorityQueueB<int> open = new PriorityQueueB<int>( (a,b) => newGrid[a]._cost.CompareTo(newGrid[b]._cost) ); open.Push(_targetX + _targetY * _map.Width); for(int i = 0; i < newGrid.Length; ++i) { newGrid[i]._cost = _map.Blocks[i].Type == BlockType.Solid ? BlockerCost : 0; newGrid[i]._nextIndex = -1; } if(blockers != null) { foreach(Point p in blockers) { newGrid[p.X + p.Y * _map.Width]._cost = BlockerCost; } } while(open.Count > 0) { // Get the lowest cost open node int nodeIndex = open.Pop(); int nodeX = nodeIndex % _map.Width; int nodeY = nodeIndex / _map.Width; for(int i = 0; i < 8; ++i) { int nextNodeX = nodeX + NeighborLookups[i*2+0]; int nextNodeY = nodeY + NeighborLookups[i*2+1]; if(nextNodeX < 0 || nextNodeX >= _map.Width || nextNodeY < 0 || nextNodeY >= _map.Height) continue; int nextNodeIndex = nextNodeX + nextNodeY * _map.Width; int nextCost = newGrid[nodeIndex]._cost + (i >= 4 ? 14 : 10); if(IsValidMove(newGrid, nodeX, nodeY, nextNodeX, nextNodeY)) { // If the neighbor is not already visited, and walkable if(newGrid[nextNodeIndex]._nextIndex == -1) { newGrid[nextNodeIndex]._cost = nextCost; newGrid[nextNodeIndex]._nextIndex = nodeIndex; // add it to the open queue open.Push(nextNodeIndex); } else // Update the neighbor if this is a shorter path if(nextCost < newGrid[nextNodeIndex]._cost) { newGrid[nextNodeIndex]._cost = nextCost; newGrid[nextNodeIndex]._nextIndex = nodeIndex; } } } } // Verify that all enemy spawn points can reach the target. if( 0 != _map.EnemySpawns.Count(sp => newGrid[sp.BlockX + sp.BlockY * _map.Width]._nextIndex < 0)) { return false; } Grid = newGrid; return true; }
private void HandleExploringMode() { if (explorePathQueue.Count == 0) { done = true; npAgentGameMode = Stage.GameMode.NP_AGENT_TREASURE_STOP; } else { // get another path from explore path queue currentPath = explorePathQueue.Dequeue(); // get first path goal nextGoal = currentPath.NextNode; // orient towards the first path goal agentObject.TurnToFace(nextGoal.Translation); } }
/// <summary> /// A very simple limited random walk. Repeatedly moves skipSteps forward then /// randomly decides how to turn (left, right, or not to turn). Does not move /// very well -- its just an example... /// </summary> public override void Update(GameTime gameTime) { stage.setInfo(15, string.Format("npAvatar: Location ({0:f0},{1:f0},{2:f0}) Looking at ({3:f2},{4:f2},{5:f2})", agentObject.Translation.X, agentObject.Translation.Y, agentObject.Translation.Z, agentObject.Forward.X, agentObject.Forward.Y, agentObject.Forward.Z)); stage.setInfo(16, string.Format("nextGoal: ({0:f0},{1:f0},{2:f0})", nextGoal.Translation.X, nextGoal.Translation.Y, nextGoal.Translation.Z)); // See if at or close to nextGoal, distance measured in the flat XZ plane float distance = Vector3.Distance( new Vector3(nextGoal.Translation.X, 0, nextGoal.Translation.Z), new Vector3(agentObject.Translation.X, 0, agentObject.Translation.Z)); if (distance <= snapDistance) { stage.setInfo(17, string.Format("distance to goal = {0,5:f2}", distance)); // snap to nextGoal and orient toward the new nextGoal nextGoal = path.NextNode; agentObject.turnToFace(nextGoal.Translation); if (path.Done) stage.setInfo(18, "path traversal is done"); else { turnCount++; stage.setInfo(18, string.Format("turnToFace count = {0}", turnCount)); } } base.Update(gameTime); // Agent's Update(); }
/// <summary> /// Check to see if a node is already in a set /// based on their position NOT distance /// </summary> /// <param name="current">a NavNode</param> /// <param name="set">the current set (either closeSet or openSet)</param> /// <returns>true if it's in, false otherwise</returns> private bool IsNodeIn(NavNode current, PriorityQueue<NavNode> set) { List<NavNode> nodes = set.GetList(); foreach (NavNode n in nodes) { if (n.Translation.X == current.Translation.X && n.Translation.Z == current.Translation.Z) return true; } return false; }
/// <summary> /// Procedurally make a path for NPAgent to traverse /// </summary> /// <returns></returns> private List<NavNode> makePath() { List<NavNode> aPath = new List<NavNode>(); int spacing = stage.Spacing; // make a simple path, show how to set the type of the NavNode outside of construction. NavNode n; n = new NavNode(new Vector3(505 * spacing, stage.Terrain.surfaceHeight(505, 505), 505 * spacing)); n.Navigatable = NavNode.NavNodeEnum.PATH; aPath.Add(n); n = new NavNode(new Vector3(500 * spacing, stage.Terrain.surfaceHeight(500, 500), 500 * spacing)); n.Navigatable = NavNode.NavNodeEnum.VERTEX; aPath.Add(n); aPath.Add(new NavNode(new Vector3(495 * spacing, stage.Terrain.surfaceHeight(495, 495), 495 * spacing), NavNode.NavNodeEnum.WAYPOINT)); aPath.Add(new NavNode(new Vector3(495 * spacing, stage.Terrain.surfaceHeight(495, 505), 505 * spacing), NavNode.NavNodeEnum.WAYPOINT)); // /* comment out rest of path to shorten for tests of NavNode.PathType values aPath.Add(new NavNode(new Vector3(100 * spacing, stage.Terrain.surfaceHeight(100, 500), 500 * spacing), NavNode.NavNodeEnum.WAYPOINT)); aPath.Add(new NavNode(new Vector3(100 * spacing, stage.Terrain.surfaceHeight(100, 100), 100 * spacing), NavNode.NavNodeEnum.WAYPOINT)); aPath.Add(new NavNode(new Vector3(500 * spacing, stage.Terrain.surfaceHeight(500, 100), 100 * spacing), NavNode.NavNodeEnum.WAYPOINT)); n = new NavNode(new Vector3(500 * spacing, stage.Terrain.surfaceHeight(500, 495), 495 * spacing)); n.Navigatable = NavNode.NavNodeEnum.A_STAR; aPath.Add(n); aPath.Add(new NavNode(new Vector3(495 * spacing, stage.Terrain.surfaceHeight(495, 105), 105 * spacing), NavNode.NavNodeEnum.WAYPOINT)); aPath.Add(new NavNode(new Vector3(105 * spacing, stage.Terrain.surfaceHeight(105, 105), 105 * spacing), NavNode.NavNodeEnum.WAYPOINT)); aPath.Add(new NavNode(new Vector3(105 * spacing, stage.Terrain.surfaceHeight(105, 495), 495 * spacing), NavNode.NavNodeEnum.WAYPOINT)); // */ shorter path tests return (aPath); }
private void Move() { // update mode for each move if (mode == ModeEnum.EXPLORING) npAgentGameMode = Stage.GameMode.NP_AGENT_EXPLORING; else if (mode == ModeEnum.TREASURE_HUNTING) npAgentGameMode = Stage.GameMode.NP_AGENT_TREASURE_HUNTING; if (!flagSignal) { AddPathToExploreQueue(); flagSignal = true; } displayAgentInfo(); // see if at or close to nextGoal, distance measured in the flat XZ plane float distance = Vector3.Distance( new Vector3(nextGoal.Translation.X, 0, nextGoal.Translation.Z), new Vector3(agentObject.Translation.X, 0, agentObject.Translation.Z)); if (distance <= snapDistance) { stage.SetInfo(17, string.Format("distance to goal = {0,5:f2}", distance)); // snap to nextGoal and orient toward the new nextGoal nextGoal = currentPath.NextNode; agentObject.TurnToFace(nextGoal.Translation); /* * Here we have two options when the current path is done * if npAgent is in TREASURE_HUNTING mode * if npAgent is in EXPLORING mode */ if (currentPath.Done) { Debug.WriteLine("Path traversal is done."); if (mode == ModeEnum.TREASURE_HUNTING) { HandleTreasureMode(); } else if (mode == ModeEnum.EXPLORING) { HandleExploringMode(); } } else { turnCount++; // stage.SetInfo(18, string.Format("turnToFace count = {0}", turnCount)); } } }
void Start() { for (int i = 0; i < kids.Count; i++) { kids[i].Group = this; } Destination = destination; NextNode = nextNode; }
public NodeUI(NavNode node) { Node = node; Circle = new HighlightCircle(node.Position); }
/// <summary> /// Create a NPC. /// AGXNASK distribution has npAgent move following a Path. /// </summary> /// <param name="theStage"> the world</param> /// <param name="label"> name of </param> /// <param name="pos"> initial position </param> /// <param name="orientAxis"> initial rotation axis</param> /// <param name="radians"> initial rotation</param> /// <param name="meshFile"> Direct X *.x Model in Contents directory </param> public NPAgent(Stage theStage, string label, Vector3 pos, Vector3 orientAxis, float radians, string meshFile) : base(theStage, label, pos, orientAxis, radians, meshFile) { IsCollidable = true; first.Name = "npFirst"; follow.Name = "npFollow"; above.Name = "npAbove"; // initialize all treasures InitializeMarkTreasures(); // initialize treasure path queue treasurePathQueue = new Queue<Path>(); // initialize exploring path queue explorePathQueue = new Queue<Path>(); // add all predefined path to explore path queue // AddPathToExploreQueue(); Path initialPath = new Path(stage, MakeExploringPaths(), Path.PathType.SINGLE, true); // set it to current path currentPath = initialPath; // set the mode mode = ModeEnum.EXPLORING; npAgentGameMode = Stage.GameMode.NP_AGENT_EXPLORING; stage.Components.Add(currentPath); nextGoal = currentPath.NextNode; agentObject.TurnToFace(nextGoal.Translation); }
// Adds a NavNode the NavArea nodes list public void AddNode(NavNode nodeToAdd){ m_areaNodes.Add(nodeToAdd); }
public List<NavNode> searchForPath(NavNode para_sourceNode, NavNode para_destNode, HashSet<int> para_untraversibleTypes) { NavGraph thisObj = this; List<int> pathIDs = navAlgorithm.searchForPath(ref thisObj,para_sourceNode,para_destNode,para_untraversibleTypes); if(pathIDs == null) { return null; } else { List<NavNode> reqData = convertIDListToNodeList(pathIDs); return reqData; } }