//마우스 버튼이 눌린경우 protected override void OnMouseDown(MouseEventArgs e) { //어느셀이 선택되었는지 확인하기 int cx = e.X / CELL_SIZE; int cy = e.Y / CELL_SIZE; base.OnMouseDown(e); if (mAStar != null) { for (int i = 0; i < MAX_UNIT; ++i) { //추적중인 유닛이면 if (mUnits[i].IsTracking()) { //유닛의 현재위치를 시작지점으로 CNaviNode pStart = CNaviNode.Create(mUnits[i].GetX(), mUnits[i].GetY()); //마우스로 클릭한 지점의 셀 위치를 끝지점으로 CNaviNode pEnd = CNaviNode.Create(cx, cy); List <CNaviNode> vecPath = new List <CNaviNode>(); //경로룰 구해서 구해지면 유닛에 설정해주기 if (mAStar.FindPath(pStart, pEnd, ref vecPath, mNavigationData)) { //경로가 구해지면 경로를 유닛에 설정해주기 mUnits[i].SetPath(vecPath); } } } } }
//해당 노드에 인접한 이동가능한 이웃노드들을 모두구한다, 리턴값은 이웃의 개수 virtual public int GetNeighbor(CNaviNode pos, ref List <CNaviNode> vecList) { int[] distx = new int[3] { -1, 0, 1 }; int[] disty = new int[3] { -1, 0, 1 }; for (int y = 0; y < 3; ++y) { for (int x = 0; x < 3; ++x) { int cx = distx[x] + pos.x; int cy = disty[y] + pos.y; if (cx == pos.x && cy == pos.y) { continue; } if (!IsValidPos(cx, cy)) { continue; } vecList.Add(CNaviNode.Create(cx, cy)); } } return(vecList.Count); }
protected override void OnMouseDown(MouseEventArgs e) { int cx = e.X / 16; int cy = e.Y / 16; base.OnMouseDown(e); if (m_PathFinding != null) { for (int i = 0; i < MAX_UNIT; ++i) { if (m_pUnits[i].IsTracking()) { CNaviNode pStart = CNaviNode.Create(m_pUnits[i].GetX(), m_pUnits[i].GetY()); CNaviNode pEnd = CNaviNode.Create(cx, cy); List <CNaviNode> vecPath = new List <CNaviNode>(); if (!m_PathFinding.FindPath(pStart, pEnd, ref vecPath, m_ND)) { } else { m_pUnits[i].SetPath(vecPath); } } } } }
public void Copy(CNaviNode pNode) { x = pNode.x; y = pNode.y; dist = pNode.dist; depth = pNode.depth; pParent = pNode.pParent; }
//주어진 노드의 내용을 복사하기 public void Copy(CNaviNode node) { x = node.x; y = node.y; dist = node.dist; depth = node.depth; parentNode = node.parentNode; }
public static CNaviNode Create(int sx, int sy) { CNaviNode pNode = new CNaviNode(); pNode.x = sx; pNode.y = sy; return(pNode); }
public void CalcDist(CNaviNode pDest, int cdepth) { int deltx = pDest.x - x; int delty = pDest.y - y; dist = (deltx * deltx) + (delty * delty); depth = cdepth; }
public bool IsSamePos(CNaviNode pNode) { if (x != pNode.x || y != pNode.y) { return(false); } return(true); }
public CNaviNode Clone() { CNaviNode pNode = new CNaviNode(); pNode.x = x; pNode.y = y; pNode.dist = dist; pNode.depth = depth; pNode.pParent = null; return(pNode); }
//닫힌노드에 해당 노드가 있는지 확인한다 private bool FindFromCloseNode(CNaviNode pNode) { for (int i = 0; i < m_vecCloseNode.Count; ++i) { if (m_vecCloseNode[i].IsSamePos(pNode)) { return(true); } } return(false); }
//이노드의 내용을 복사한 새로운 노드를 구성 public CNaviNode Clone() { CNaviNode node = new CNaviNode(); node.x = x; node.y = y; node.dist = dist; node.depth = depth; node.parentNode = null; return(node); }
//열란노드에 노드 삽입, 중복된 노드가 삽입되지 않도록 처리한다 private void InsertOpenNode(CNaviNode pNode) { for (int i = 0; i < mOpenNode.Count; ++i) { if (mOpenNode[i].IsSamePos(pNode)) { InsertCloseNode(mOpenNode[i]); mOpenNode[i] = pNode; return; } } mOpenNode.Add(pNode); }
public static CNaviNode Create(int sx, int sy, int dx, int dy, int dep) { CNaviNode pNode = new CNaviNode(); pNode.x = sx; pNode.y = sy; int deltx = dx - sx; int delty = dy - sy; pNode.dist = (deltx * deltx) + (delty * delty); pNode.depth = dep; return(pNode); }
//노드 p1이 노드 p2보다 저비용이라면(거리가 더가까우며, 탐색깊이가 더 작은지) true private bool NodeCompare(CNaviNode p1, CNaviNode p2) { if (p1.dist < p2.dist) { return(true); } if (p1.dist > p2.dist) { return(false); } if (p1.depth <= p2.depth) { return(true); } return(false); }
//해당 지점이 이동가능한 지점인가 확인한다 virtual public bool IsValidPos(CNaviNode pos) { if (pos.x < 0 || pos.x >= m_iWidth) { return(false); } if (pos.y < 0 || pos.y >= m_iHeight) { return(false); } if (m_MapData[(pos.y * m_iWidth) + pos.x] == 0) { return(false); } return(true); }
//해당 지점이 이동가능한 지점인가 확인한다 virtual public bool IsValidPos(CNaviNode pos) { //맵을 벗어난 지점인가? if (pos.x < 0 || pos.x >= mWidth) { return(false); } //맵을 벗어난 지점인가? if (pos.y < 0 || pos.y >= mHeight) { return(false); } //이동 불가능한 지점인가? if (mMapData[(pos.y * mWidth) + pos.x] == 0) { return(false); } return(true); }
/*해당 노드에 인접한 이동가능한 이웃노드들을 모두구한다, 리턴값은 이웃의 개수 * 좌상단, 좌, 좌하단, 상단, 하단, 우상단, 우, 우하단 8방향을 검사해서 * 이동가능한 지점만 vecList목록에 담는다. * */ virtual public int GetNeighbor(CNaviNode pos, ref List <CNaviNode> vecList) { int[] distx = new int[3] { -1, 0, 1 }; int[] disty = new int[3] { -1, 0, 1 }; for (int y = 0; y < 3; ++y) { for (int x = 0; x < 3; ++x) { int cx = distx[x] + pos.x; int cy = disty[y] + pos.y; //중앙 위치는 필요없다. if (cx == pos.x && cy == pos.y) { continue; } //이동불가능한 지점도 필요없음 if (!IsValidPos(cx, cy)) { continue; } //이동가능한 지점이면 목록에 추가하기 vecList.Add(CNaviNode.Create(cx, cy)); } } //구해진 목록의 개수를 리턴 return(vecList.Count); }
//부모노드 설정 public void SetParent(CNaviNode parent) { parentNode = parent; }
public void Update(CNavigationData ND, CAStarPathFinding FF) { if (!m_bMove) { if (m_Target != null) {// int dx = m_iPos[0] - m_Target.GetX(); int dy = m_iPos[1] - m_Target.GetY(); if (m_bTracking) {//타겟을 추적하는 모드라면 if (m_bStartTracking) { if (Math.Abs(dx) > 3 || Math.Abs(dy) > 3) { CNaviNode pStart = CNaviNode.Create(m_iPos[0], m_iPos[1]); CNaviNode pEnd = CNaviNode.Create(m_Target.GetX(), m_Target.GetY()); m_vecPath = new List <CNaviNode>(); if (!FF.FindPath(pStart, pEnd, ref m_vecPath, ND)) { } else { m_bMove = true; } } } } else {//타겟을 회피하는 모드다 if (Math.Abs(dx) < 4 && Math.Abs(dy) < 4 && !m_bMove) { while (true) { int cx = m_RND.Next(ND.GetWidth()); int cy = m_RND.Next(ND.GetHeight()); if (ND.IsValidPos(cx, cy)) { m_vecPath = new List <CNaviNode>(); CNaviNode pStart = CNaviNode.Create(m_iPos[0], m_iPos[1]); CNaviNode pEnd = CNaviNode.Create(cx, cy); if (!FF.FindPath(pStart, pEnd, ref m_vecPath, ND)) { continue; } else { m_bMove = true; break; } } } } } } } else { if (m_vecPath == null) { m_bMove = false; } else { int curindex = m_vecPath.Count - 1; if (curindex < 0) { m_bMove = false; m_vecPath = null; } else { m_iPos[0] = m_vecPath[curindex].x; m_iPos[1] = m_vecPath[curindex].y; m_vecPath.RemoveAt(curindex); } } } }
//시작 위치 PStart에서 목표위치 pEnd까지의 경로를 구한다. 경로가 구해진경우 true그렇지 않은경우 fale //finalPath : 구해진경로 //navigation : 지형데이터를 제공한다 public bool FindPath(CNaviNode startPos, CNaviNode endPos, ref List <CNaviNode> finalPath, CNavigationData navigation) { Delete(); CNaviNode currentNode = startPos.Clone(); /* * insert start position to open node, 시작점을 열린노드에 삽입한다. * */ mOpenNode.Add(currentNode); int depth = 0; currentNode.depth = depth; List <CNaviNode> childs; childs = new List <CNaviNode>(); while (true) { if (mOpenNode.Count == 0) { //if opennode has not contents, it's meaning that path not found. 만일 열린노드에 더이상 데이터가 없다면 길이 존재하지 않는것이다. break; } currentNode = mOpenNode[0]; //get first content, 열린노드의 가장처음항목을 하나 가져온다 mOpenNode.RemoveAt(0); //delete content from open node, 가져온것은 열린노드에서 제거한다 if (endPos.IsSamePos(currentNode)) //if that node is end position, we found path, 만일 가져온 노드가 목표점이라면 해당 노드를 패스목록에 추가하고 길탐색을 종료한다 { while (currentNode != null) //tracking it's parent node for it's parent is null { finalPath.Add(currentNode); //add node to path list currentNode = currentNode.GetParent(); //get current node's parent } return(true); } currentNode = InsertCloseNode(currentNode); //insert current node to close list, 목표점이 아니면 해당 노드를 닫힌노드에 삽입한다. ++depth; //탐색깊이를 하나 증가 시킨다 childs.Clear(); navigation.GetNeighbor(currentNode, ref childs); //해당노드의 인접한 노드들을 모두 가져와서 for (int i = 0; i < childs.Count; ++i) { if (FindFromCloseNode(childs[i])) //만일 닫힌노드에 있는것이면 무시하고 { continue; } //닫힌노드에 없는것이라면, 거리를 구한다음에 열린노드에 삽입한다. childs[i].CalcDist(endPos, depth); childs[i].SetParent(currentNode); InsertOpenNode(childs[i]); } //열린노드를 비용에 따라서 정렬한다 SortOpenNode(); } Delete(); return(false); }
//닫힌노드에 삽입 private CNaviNode InsertCloseNode(CNaviNode pNode) { mCloseNode.Add(pNode); return(pNode); }
//매프레임 호출되어 유닛을 이동시킴 public void Update(CNavigationData ND, CAStarPathFinding FF) { //현재 이동중이지 않을 경우 if (!m_bMove) { //묙표유닛이 존재한다면 if (m_Target != null) {// //묙표유닛과 자신과의 거리를 구한다 int dx = m_iPos[0] - m_Target.GetX(); int dy = m_iPos[1] - m_Target.GetY(); if (m_bTracking) {//타겟을 자동추적하는 모드라면 //추적중이라면 if (m_bStartTracking) { //목표와의 거리가 3셀이상이면 if (Math.Abs(dx) > 3 || Math.Abs(dy) > 3) { //나의 위치를 시작점, 목표위치를 끝점으로해서 CNaviNode pStart = CNaviNode.Create(m_iPos[0], m_iPos[1]); CNaviNode pEnd = CNaviNode.Create(m_Target.GetX(), m_Target.GetY()); //경로를 구하고 m_vecPath = new List <CNaviNode>(); if (!FF.FindPath(pStart, pEnd, ref m_vecPath, ND)) { } else { //경로가 구해졌으면 유닛이동을 활성화 m_bMove = true; } } } } else {//타겟을 회피하는 모드다 //목표와의 거리가 4셀 이하이고, 현재 이동중이지 않으면 if (Math.Abs(dx) < 4 && Math.Abs(dy) < 4 && !m_bMove) { //무한반복 while (true) { //맵에서 임의의 위치를 하나 선택하고 int cx = m_RND.Next(ND.GetWidth()); int cy = m_RND.Next(ND.GetHeight()); //해당 위치가 이동가능한곳이면 if (ND.IsValidPos(cx, cy)) { //유닛의 현재 위치를 시작점, 위에서 선택한 임의의 위치를 끝점으로 해서 CNaviNode pStart = CNaviNode.Create(m_iPos[0], m_iPos[1]); CNaviNode pEnd = CNaviNode.Create(cx, cy); //경로를 구하고 m_vecPath = new List <CNaviNode>(); if (!FF.FindPath(pStart, pEnd, ref m_vecPath, ND)) { //경로가 구해지지 않았으면 while 루프를 다시 반복 continue; } else { //경로가 구해졌으면 유닛을 이동상태로 설정하고, while 루프를 종료 m_bMove = true; break; } } } } } } } else //유닛이 현재 이동중인경우면 { //경로가 존재하지 않으면, 이동모드를 중지 if (m_vecPath == null) { m_bMove = false; } else { int curindex = m_vecPath.Count - 1; //경로의 목표점에 도달했으면 if (curindex < 0) { //이동모드를 중지하고, 경로는 클리어 m_bMove = false; m_vecPath = null; } else { //경로의 현재 점을 유닛의 위치로 설정하고, 사용한 좌표는 경로 목록에서 제거하기 m_iPos[0] = m_vecPath[curindex].x; m_iPos[1] = m_vecPath[curindex].y; m_vecPath.RemoveAt(curindex); } } } }
public void SetParent(CNaviNode p) { pParent = p; }