/// <summary> /// ノード生成する /// </summary> /// <param name="x">そのノードのx座標</param> /// <param name="y">そのノードのy座標</param> /// <returns></returns> public A_Node Get_Node(int x, int y) { // 目的地の1つ手前の座標を探す foreach (var before_one in goal_before_one) { if (x == goal_x || y == goal_y) { allowdiag = false; } } int idx = layer.To_Index(x, y); if (pool.ContainsKey(idx)) { // 既に存在しているのでプーリングから取得 return(pool[idx]); } // ないので新規作成 var node = new A_Node(x, y); pool[idx] = node; // ヒューリスティック・コストを計算する node.Calc_Heuristic(allowdiag, goal_x, goal_y); return(node); }
/// <summary> /// 指定の座標にあるノードをオープンする /// </summary> /// <param name="x" >オープンするノードの座標</param> /// <param name="y" >オープンするノードの座標</param> /// <param name="cost" >オープンするノードのコスト</param> /// <param name="parent">親ノード</param> /// <returns>オープンしたノード</returns> public A_Node Open_Node(int x, int y, int cost, A_Node parent) { // 座標をチェック if (layer.Is_Out_Of_Range(x, y)) { // 領域外 return(null); } if (layer.Get(x, y) > 1) { // 通過できない return(null); } // ノードを取得する A_Node node = Get_Node(x, y); if (node.Is_None() == false) { // 既にOpenしているので何もしない return(null); } // Openする node.Open(parent, cost); Add_Open_List(node); return(node); }
/// <summary> /// 最小スコアのノードを取得する /// </summary> /// <returns>最小スコアのノード</returns> public A_Node Search_Min_Score_Node() { // 最小スコア int min = 9999; // 最小実コスト int min_cost = 9999; A_Node min_node = null; foreach (A_Node node in open_list) { int score = node.GetScore(); if (score > min) { // スコアが大きい continue; } if (score == min && node.Cost >= min_cost) { // スコアが同じときは実コストも比較する continue; } // 最小値更新. min = score; min_cost = node.Cost; min_node = node; } return(min_node); }
void ConnectNodes() { int nodeCounter = 0; foreach (A_Node node in nodes) { A_Node tmp = SearchForNode(new Vector3(node.position.x, node.position.y, node.position.z - 1)); if (tmp != null) { node.connections.Add(tmp); } tmp = SearchForNode(new Vector3(node.position.x, node.position.y, node.position.z + 1)); if (tmp != null) { node.connections.Add(tmp); } tmp = SearchForNode(new Vector3(node.position.x - 1, node.position.y, node.position.z)); if (tmp != null) { node.connections.Add(tmp); } tmp = SearchForNode(new Vector3(node.position.x + 1, node.position.y, node.position.z)); if (tmp != null) { node.connections.Add(tmp); } nodeCounter++; } }
void SortNodes(List <A_Node> items) { if (items.Count > 0) { bool isSorted = false; int lUnsorted = items.Count; while (!isSorted) { isSorted = true; for (int i = 0; i < lUnsorted; i++) { if (i + 1 < items.Count) { items[i].CalF(); items[i + 1].CalF(); if (items[i + 1].f_score < items[i].f_score) { A_Node tmp = items[i + 1]; items[i + 1] = items[i]; items[i] = tmp; } } } lUnsorted--; } } }
void MakeNodes() { Collider[] coll; bool waitForNext = false; bool doPlayerOnce = false; bool doTargetOnce = false; Vector3 lastNodePos = Vector3.zero; int currNode = 0; for (float i = -size.x; i < size.x; i++) { for (float j = -size.z; j < size.z; j++) { coll = Physics.OverlapBox(new Vector3(i, size.y, j), sizeOfBox / 2); foreach (Collider col in coll) { foreach (string tag in tags) { if (col.gameObject.CompareTag(tag) && !waitForNext) { nodes.Add(new A_Node(2, new Vector3(i, size.y, j))); waitForNext = true; } } if (col.gameObject.CompareTag(this.gameObject.tag) && !waitForNext) { if (!doPlayerOnce) { nodes.Add(new A_Node(0, new Vector3(i, size.y, j))); startNode = nodes[currNode]; waitForNext = true; doPlayerOnce = true; } } if (col.gameObject.CompareTag(target.gameObject.tag) && !waitForNext) { if (!doTargetOnce) { nodes.Add(new A_Node(-1, new Vector3(i, size.y, j))); targetNode = nodes[currNode]; waitForNext = true; doTargetOnce = true; } } } if (!waitForNext) { nodes.Add(new A_Node(1, new Vector3(i, size.y, j))); } currNode++; waitForNext = false; } } foreach (A_Node node in nodes) { node.h_score = (node.position.x + targetNode.position.x) + (node.position.z + targetNode.position.z); } ConnectNodes(); }
void ReValueNodes() { Collider[] coll; bool waitForNext = false; bool doPlayerOnce = false; bool doTargetOnce = false; Vector3 lastNodePos = Vector3.zero; foreach (A_Node node in nodes) { coll = Physics.OverlapBox(node.position, sizeOfBox / 2); foreach (Collider col in coll) { foreach (string tag in tags) { if (col.gameObject.CompareTag(tag) && !waitForNext) { node.g_score = 2; waitForNext = true; } } if (col.gameObject.CompareTag(this.gameObject.tag) && !waitForNext) { if (!doPlayerOnce) { node.g_score = 0; startNode = node; waitForNext = true; doPlayerOnce = true; transform.position = node.position; } } if (col.gameObject.CompareTag(target.gameObject.tag) && !waitForNext) { if (!doTargetOnce) { node.g_score = -1; targetNode = node; waitForNext = true; doTargetOnce = true; transform.position = node.position; } } } if (!waitForNext) { node.g_score = 1; } node.pastNode = null; waitForNext = false; } foreach (A_Node node in nodes) { node.h_score = (node.position.x + targetNode.position.x) + (node.position.z + targetNode.position.z); } }
bool isInClosesd(A_Node value) { for (int i = 0; i < closedList.Count; i++) { if (closedList[i] == value) { return(true); } } return(false); }
bool isInOpen(A_Node value) { for (int i = 0; i < openList.Count; i++) { if (openList[i] == value) { return(true); } } return(false); }
void LookForPath() { // do some sort of for loop in here currentNode = startNode; bool pathFound = false; int operations = 0; while (!pathFound) { if (!isInClosesd(currentNode)) { closedList.Add(currentNode); } for (int i = 0; i < currentNode.connections.Count; i++) { if (!isInOpen(currentNode.connections[i]) && !isInClosesd(currentNode.connections[i])) { currentNode.connections[i].g_score += currentNode.g_score; if (currentNode.connections[i].pastNode == null) { currentNode.connections[i].pastNode = currentNode; } openList.Add(currentNode.connections[i]); } } SortNodes(openList); if (openList.Count > 0) { currentNode = openList[0]; openList.Remove(currentNode); } if (currentNode == targetNode) { pathFound = true; } operations++; } Debug.Log(operations); pathFound = false; while (!pathFound) { if (currentNode != null) { path.Add(currentNode); currentNode = currentNode.pastNode; } else { pathFound = true; } } }
void CreatePath() { targetNode = null; startNode = null; //RemoveAll(nodes); RemoveAll(openList); RemoveAll(closedList); RemoveAll(path); currentNode = null; startNode = null; targetNode = null; if (nodes.Count > 0) { ReValueNodes(); } else { MakeNodes(); } LookForPath(); nextPath = path.Count - 1; }
/// <summary> /// 周囲をOpenする /// </summary> /// <param name="parent"></param> public void Open_Around(A_Node parent) { // 基準座標(X) int xbase = parent.X; // 基準座標(Y) int ybase = parent.Y; // コスト int cost = parent.Cost; // 一歩進むので+1する cost += Define_Value.TILE_SCALE; if (allowdiag) { // 8方向を開く for (int j = 0; j <= 4; ++j) { for (int i = 0; i <= 4; ++i) { int x = xbase + i - Define_Value.TILE_SCALE; // -1~1 int y = ybase + j - Define_Value.TILE_SCALE; // -1~1 Open_Node(x, y, cost, parent); } } } else { // 4方向を開く var x = xbase; var y = ybase; // 上から時計回り Open_Node(x, y - Define_Value.TILE_SCALE, cost, parent); Open_Node(x - Define_Value.TILE_SCALE, y, cost, parent); Open_Node(x, y + Define_Value.TILE_SCALE, cost, parent); Open_Node(x + Define_Value.TILE_SCALE, y, cost, parent); } }
/// <summary> /// 部屋にいるときの移動を管理 /// </summary> public void Stack_List() { // 現在の座標を取得 Point2 start = Get_Now_Position(enemy_object.GetComponent <Enemy>()); // 指定の部屋の入口(出口)を探す Point2 goal = Get_Goal_Position(now_room_number); // 入口(出口)の1つ前の座標を取得 goal_before_one = new List <Point2>(); Get_Goal_Before_One(goal); if (goal_before_one.Count == 0) { Debug.Log("入り口前取れてない"); } // 今いる座標 var start_position = new Vector2Int { x = start.x, y = start.y }; // 今いる部屋の中の座標に置き換える start_position = In_Room_Coodinates(start_position); // 目的地の座標 goal_position = new Vector2Int { x = goal.x, y = goal.y }; // 今いる部屋の中の座標に置き換える goal_position = In_Room_Coodinates(goal_position); // 座標を知ってる構造体のリスト point_list = new List <Point2>(); // 斜め移動を許可 var allowdiag = true; var node_manager = new A_Node_Manager(now_room_number, goal.x, goal.y, goal_before_one, allowdiag); // スタート地点のノード取得 // スタート地点なのでコストは「0」 A_Node node = node_manager.Open_Node((int)start_position.x, (int)start_position.y, 0, null); node_manager.Add_Open_List(node); // 試行回数 int counter = 0; while (counter < 10) //TODO:マジックナンバー { node_manager.Remove_Open_List(node); // 周囲を開く node_manager.Open_Around(node); // 最小スコアのノードを探す. node = node_manager.Search_Min_Score_Node(); if (node == null) { // 袋小路なのでおしまい. break; } // ゴールにたどり着いた // TODO:たどり着かない場合がある。 if (node.X == goal_position.x && node.Y == goal_position.y) { node_manager.Remove_Open_List(node); // パスを取得する node.GetPath(point_list); // 反転する point_list.Reverse(); break; } } }
void CheckNodes(A_Node a, A_Node b) { }
/// <summary> /// ノードをオープンリストから削除する /// </summary> /// <param name="node">不要ノード</param> public void Remove_Open_List(A_Node node) { open_list.Remove(node); }
/// <summary> /// ノードをオープンリストに追加する /// </summary> /// <param name="node">オープンにしたノード</param> public void Add_Open_List(A_Node node) { open_list.Add(node); }
/// <summary> /// ステータスをOpenにする /// </summary> /// <param name="parent_">親ノード</param> /// <param name="cost_">次開けるもののコスト</param> public void Open(A_Node set_parent, int set_cost) { status = eNode_Status.Open; cost = set_cost; parent = set_parent; }