33,010
社区成员
发帖
与我相关
我的任务
分享
// Astar.h
#pragma once
#include "MemAlloc.h"
#include <vector>
#include <list>
using namespace std;
class CMapNode
{
public:
CMapNode(){Clear();}
void Clear()
{
m_Point.x = 0;
m_Point.y = 0;
m_nF = 0;
m_nG = 0;
m_nH = 0;
m_pParent = NULL;
m_nSerialNumber = 0;
}
inline void* operator new(size_t size){return m_memAlloc.Alloc(size);}
inline void operator delete(void* p){m_memAlloc.Delete(p);}
public:
CPoint m_Point;
int m_nF;
int m_nG;
int m_nH;
size_t m_nSerialNumber; //代表这个节点的编号
CMapNode* m_pParent;
private:
static CMemAlloc m_memAlloc;
};
//这里面统一不能通过的点为1;能通过的为0
class CAStar
{
public:
CAStar(void);
~CAStar(void);
bool FindPath(CPoint psrc, CPoint pdes);
void InitMap(CSize mapSize, long* pObstacle);
vector<CPoint> GetPointPath()const;
void PrintMap()const;
void PrintMap(CSize mapSize, long* map)const;
private:
bool IsPointInMap(const CPoint& pt)const;
void Init();
void Destroy();
void ResetPath();
CMapNode* GetBestNode();
CMapNode* CreateMapNode(const CPoint& pt, CMapNode* parent = NULL);
void CheckCircumjacentNode(CMapNode* pNode);
void CheckACircumjacentNode(CMapNode* pSrcNode, const CPoint& desPt);
CMapNode* GetOpenNode(const CPoint& pt);
void AddToOpenList(CMapNode* pt);
void RemoveOpenListFirstElement();
size_t GetMinChildIdx(size_t parentIdx)const;
inline int GetG(const CPoint& pt1, const CPoint& pt2)const;
void ValuePoint(CPoint ptSrc, CPoint& ptDest, bool bCheckNPC = false);
inline bool IsCanPass(const CPoint& pt){return 0 == m_pnMap[GetSerialNumber(pt)];}
inline size_t GetSerialNumber(const CPoint& pt)const{return pt.y * m_MapSize.cx + pt.x;}
private:
long* m_pnMap; //用一维数组来表示一张地图
size_t m_MapLenth; //就是地图的大小
CSize m_MapSize;
list<CMapNode*> m_Close;
CMapNode** m_pOpen;
CMapNode* m_DesNode;
size_t m_OpenNodeNum;
CPoint m_DesPt;
CPoint m_OffsetPt;
};
inline int abs(int n)
{
if (n > 0)
{
return n;
}
else
{
return -n;
}
}
// MemAlloc.h
#pragma once
#include <vector>
#include <string>
using namespace std;
class CMemError
{
public:
CMemError(const char* p){m_strError = p;}
const char* GetErrorMsg()const{return m_strError.c_str();}
private:
string m_strError;
};
struct MemList
{
MemList* pNext;
};
// 这个只能用于单线程!!
class CMemAlloc
{
public:
enum{
ChunkSize = 256, //一块内存有多少个小内存组成
MinMemSize = 4, //一个内存最小为4字节
};
CMemAlloc(void);
~CMemAlloc(void);
inline void* Alloc(size_t size);
inline void Delete(void* p);
private:
inline void AllocChunk(size_t size);
private:
vector<char*> m_MemChunk; //申请的所有内存块
MemList* m_pMemList; //备用内存
size_t m_nMemSize; //每一个内存的大小
};
void* CMemAlloc::Alloc(size_t size)
{
if (0 == m_nMemSize)
{
m_nMemSize = size;
}
if (m_nMemSize != size)
{
throw CMemError("一个 CMemAlloc 对象只能分配一种大小的内存");
}
if (NULL == m_pMemList)
{
AllocChunk(size);
}
void* pRet = reinterpret_cast<void*>(m_pMemList);
m_pMemList = m_pMemList->pNext;
return pRet;
}
void CMemAlloc::Delete(void* p)
{
if (NULL == p) //删除空指针是安全的
{
return;
}
reinterpret_cast<MemList*>(p)->pNext = m_pMemList;
m_pMemList = reinterpret_cast<MemList*>(p);
}
void CMemAlloc::AllocChunk(size_t size)
{
if (size < MinMemSize)
{
size = MinMemSize;
}
char* p = reinterpret_cast<char*>(malloc(ChunkSize * size));
MemList* pList;
for (int i = 0; i < ChunkSize; ++i)
{
pList = reinterpret_cast<MemList*>(p + (i * size));
pList->pNext = m_pMemList;
m_pMemList = pList;
}
m_MemChunk.push_back(p);
}
// MemAlloc.cpp
#include "StdAfx.h"
#include "MemAlloc.h"
CMemAlloc::CMemAlloc(void)
{
m_pMemList = NULL;
m_nMemSize = 0;
}
CMemAlloc::~CMemAlloc(void)
{
m_pMemList = NULL;
for (vector<char*>::iterator it = m_MemChunk.begin(); it != m_MemChunk.end(); ++it)
{
free(*it);
}
m_MemChunk.clear();
}
// CAstar.cpp
#include "StdAfx.h"
#include ".\astar.h"
#include <cstring>
#include <fstream>
using namespace std;
CMemAlloc CMapNode::m_memAlloc;
CAStar::CAStar(void)
{
Init();
}
CAStar::~CAStar(void)
{
Destroy();
}
void CAStar::InitMap(CSize mapSize, long* pObstacle)
{
Destroy();
m_MapSize = mapSize;
//将地图的周边都加一个位置,设置成障碍物,以免寻路的时候,会走的边界以外去
m_MapSize.cx += 2;
m_MapSize.cy += 2;
m_OffsetPt.x = -1;
m_OffsetPt.y = -1;
m_MapLenth = m_MapSize.cx * m_MapSize.cy;
m_pnMap = new long[m_MapLenth];
memset(m_pnMap, 0, sizeof(long) * m_MapLenth);
for (int i = 0; i < m_MapSize.cx; ++i)
{
m_pnMap[i] = 1; //上底
m_pnMap[m_MapLenth - i - 1] = 1; //下底
}
for (int i = 0; i < m_MapLenth; i += m_MapSize.cx)
{
m_pnMap[i] = 1; //左边
m_pnMap[i + m_MapSize.cx - 1] = 1;//右边
}
//设置地图中间的障碍物
for (int i = 0; i < mapSize.cy; ++i)
{
memcpy(m_pnMap + (m_MapSize.cx * (i + 1) + 1), pObstacle + (mapSize.cx * i), sizeof(long) * mapSize.cx);
}
}
bool CAStar::FindPath(CPoint psrc, CPoint pdes)
{
//因为我们加了地图边界
psrc -= m_OffsetPt;
pdes -= m_OffsetPt;
if (!IsPointInMap(psrc) || !IsPointInMap(pdes))
{
return false;
}
ResetPath();
ValuePoint(psrc, pdes, true);
size_t desSerialNumber = GetSerialNumber(psrc);
m_DesPt = psrc;
m_pOpen = new CMapNode*[m_MapSize.cx * m_MapSize.cy];
CMapNode* pNode = CreateMapNode(pdes);
AddToOpenList(pNode);
while(true)
{
pNode = GetBestNode();
if (NULL == pNode) //没有路可走了
{
return false;
}
if (pNode->m_nSerialNumber == desSerialNumber)//找到目的地了
{
m_DesNode = pNode;
return true;
}
CheckCircumjacentNode(pNode);
}
return true;
}
vector<CPoint> CAStar::GetPointPath()const
{
vector<CPoint> vpt;
CPoint pt;
CMapNode* pNode = m_DesNode;
while(NULL != pNode)
{
pt.x = pNode->m_Point.x + m_OffsetPt.x;
pt.y = pNode->m_Point.y + m_OffsetPt.y;
vpt.push_back(pt);
pNode = pNode->m_pParent;
}
return vpt;
}
bool CAStar::IsPointInMap(const CPoint& pt)const
{
if (pt.x < 1 || pt.y < 1)
{
return false;
}
else if (pt.x >= m_MapSize.cx - 1 || pt.y >= m_MapSize.cy - 1)
{
return false;
}
else
{
return true;
}
}
void CAStar::PrintMap()const
{
if (NULL == m_pnMap)
{
return;
}
ofstream m_file;
m_file.open("mmap.txt", ios_base::out | ios_base::app);
for (int i = 0; i < m_MapSize.cy; ++i)
{
CString strLine;
for (int j = 0; j < m_MapSize.cx; ++j)
{
if (0 == m_pnMap[(i * m_MapSize.cx) + j])
{
strLine += '0';
}
else if(10 == m_pnMap[(i * m_MapSize.cx) + j])
{
strLine += '+';
}
else
{
strLine += '-';
}
}
m_file << (LPCSTR)strLine << endl;
}
m_file.flush();
m_file.close();
}
void CAStar::PrintMap(CSize mapSize, long* map)const
{
if (NULL == m_pnMap)
{
return;
}
ofstream m_file;
m_file.open("mmap.txt", ios_base::out | ios_base::app);
for (int i = 0; i < mapSize.cy; ++i)
{
CString strtemp;
CString strLine;
for (int j = 0; j < mapSize.cx; ++j)
{
strtemp.Format("%d", map[(i * m_MapSize.cx) + j]);
strLine += strtemp;
}
m_file << (LPCSTR)strLine << endl;
}
m_file.flush();
m_file.close();
}
void CAStar::Init()
{
m_pnMap = NULL;
m_pOpen = NULL;
m_DesNode = NULL;
m_OpenNodeNum = 0;
m_MapSize.cx = 0;
m_MapSize.cy = 0;
}
void CAStar::Destroy()
{
delete m_pnMap;
m_pnMap = NULL;
m_MapSize.cx = 0;
m_MapSize.cy = 0;
ResetPath();
}
void CAStar::ResetPath()
{
for(int i = 0; i < m_OpenNodeNum; ++i)
{
ASSERT(m_pOpen);
delete m_pOpen[i];
m_pOpen[i] = NULL;
}
delete[] m_pOpen;
m_pOpen = NULL;
m_OpenNodeNum = 0;
for (list<CMapNode*>::iterator it = m_Close.begin(); it != m_Close.end(); ++it)
{
delete *it;
}
m_Close.clear();
m_DesNode = NULL; //它同时也在m_Close里面,所以这里就不用delete了
}
CMapNode* CAStar::GetBestNode()
{
if (m_OpenNodeNum <= 0)
{
return NULL;
}
CMapNode* temp = m_pOpen[0];
m_Close.push_back(temp);
m_pnMap[temp->m_nSerialNumber] = 10;//将关闭列表中的结点通通设为不可达
RemoveOpenListFirstElement();
return temp;
}
CMapNode* CAStar::CreateMapNode(const CPoint& pt, CMapNode* parent /*= NULL*/)
{
CMapNode* pNode =new CMapNode;
pNode->m_Point = pt;
pNode->m_nSerialNumber = GetSerialNumber(pt);
if (NULL != parent)
{
pNode->m_pParent = parent;
pNode->m_nG = GetG(pt, parent->m_Point) + parent->m_nG;
pNode->m_nH = (abs(pt.x - m_DesPt.x) + abs(pt.y - m_DesPt.y)) * 10;
pNode->m_nF = pNode->m_nG + pNode->m_nH;
}
return pNode;
}
void CAStar::CheckCircumjacentNode(CMapNode* pNode)
{
ASSERT(pNode);
CPoint tempPt;
//右边
CheckACircumjacentNode(pNode, CPoint(pNode->m_Point.x + 1, pNode->m_Point.y));
//右下
CheckACircumjacentNode(pNode, CPoint(pNode->m_Point.x + 1, pNode->m_Point.y + 1));
//下边
CheckACircumjacentNode(pNode, CPoint(pNode->m_Point.x, pNode->m_Point.y + 1));
//左下
CheckACircumjacentNode(pNode, CPoint(pNode->m_Point.x - 1, pNode->m_Point.y + 1));
//左边
CheckACircumjacentNode(pNode, CPoint(pNode->m_Point.x - 1, pNode->m_Point.y));
//左上
CheckACircumjacentNode(pNode, CPoint(pNode->m_Point.x - 1, pNode->m_Point.y - 1));
//上边
CheckACircumjacentNode(pNode, CPoint(pNode->m_Point.x, pNode->m_Point.y - 1));
//右上
CheckACircumjacentNode(pNode, CPoint(pNode->m_Point.x + 1, pNode->m_Point.y - 1));
}
void CAStar::CheckACircumjacentNode(CMapNode* pSrcNode, const CPoint& desPt)
{
ASSERT(pSrcNode);
CMapNode* DesNode;
if (IsCanPass(desPt))
{
DesNode = GetOpenNode(desPt);
if (NULL == DesNode)
{
DesNode = CreateMapNode(desPt, pSrcNode);
AddToOpenList(DesNode);
}
else
{
if (DesNode->m_nG > (pSrcNode->m_nG + GetG(desPt, pSrcNode->m_Point)))
{
DesNode->m_pParent = pSrcNode;
DesNode->m_nG = pSrcNode->m_nG + GetG(desPt, pSrcNode->m_Point);
DesNode->m_nF = DesNode->m_nG + DesNode->m_nH;
}
}
}
}
CMapNode* CAStar::GetOpenNode(const CPoint& pt)
{
size_t serialNum = GetSerialNumber(pt);
for (int i = 0; i < m_OpenNodeNum; ++i)
{
if (serialNum == m_pOpen[i]->m_nSerialNumber)
{
return m_pOpen[i];
}
}
return NULL;
}
void CAStar::AddToOpenList(CMapNode* pNode)
{
m_pOpen[m_OpenNodeNum] = pNode;
++m_OpenNodeNum;
size_t childIdx = m_OpenNodeNum;
size_t parentIdx = childIdx >> 1;
while(parentIdx > 0 && m_pOpen[parentIdx - 1]->m_nF > m_pOpen[childIdx - 1]->m_nF)
{
CMapNode* temp;
temp = m_pOpen[parentIdx - 1];
m_pOpen[parentIdx - 1] = m_pOpen[childIdx - 1];
m_pOpen[childIdx - 1] = temp;
childIdx = parentIdx;
parentIdx = childIdx >> 1;
}
}
void CAStar::RemoveOpenListFirstElement()
{
if (0 == m_OpenNodeNum)
{
return;
}
--m_OpenNodeNum;
m_pOpen[0] = m_pOpen[m_OpenNodeNum];
m_pOpen[m_OpenNodeNum] = NULL;
size_t parentIdx = 1;
size_t minChildIdx = GetMinChildIdx(parentIdx);
while(minChildIdx <= m_OpenNodeNum && m_pOpen[parentIdx - 1]->m_nF > m_pOpen[minChildIdx - 1]->m_nF)
{
CMapNode* temp;
temp = m_pOpen[parentIdx - 1];
m_pOpen[parentIdx - 1] = m_pOpen[minChildIdx - 1];
m_pOpen[minChildIdx - 1] = temp;
parentIdx = minChildIdx;
minChildIdx = GetMinChildIdx(parentIdx);
}
}
size_t CAStar::GetMinChildIdx(size_t parentIdx)const
{
size_t childIdx = parentIdx * 2;
if (childIdx < m_OpenNodeNum)
{
if (m_pOpen[childIdx - 1]->m_nF > m_pOpen[childIdx]->m_nF)
{
return childIdx + 1;
}
else
{
return childIdx;
}
}
else if (childIdx == m_OpenNodeNum)
{
return childIdx;
}
else
{
return m_OpenNodeNum + 1; //返回一个不全法的位置,表示它没有孩子了
}
}
int CAStar::GetG(const CPoint& pt1, const CPoint& pt2)const
{
if ((pt1.x - pt2.x) && (pt1.y - pt2.y)) //斜角
{
return 14;
}
else
{
return 10;
}
}
void CAStar::ValuePoint(CPoint ptSrc, CPoint& ptDest, bool bCheckNPC /*= false*/)//修改ptDest
{
//查看目标点有没有被包围,如果是的话,帮它选一个最近的目标点,要在是NPC寻路的情况下
if (true == bCheckNPC)
{
int nObstacleNum = 0;
if (!IsCanPass(CPoint(ptDest.x + 1, ptDest.y)))
{
++nObstacleNum;
}
if (!IsCanPass(CPoint(ptDest.x + 1, ptDest.y + 1)))
{
++nObstacleNum;
}
if (!IsCanPass(CPoint(ptDest.x, ptDest.y + 1)))
{
++nObstacleNum;
}
if (!IsCanPass(CPoint(ptDest.x - 1, ptDest.y + 1)))
{
++nObstacleNum;
}
if (!IsCanPass(CPoint(ptDest.x - 1, ptDest.y)))
{
++nObstacleNum;
}
if (!IsCanPass(CPoint(ptDest.x - 1, ptDest.y - 1)))
{
++nObstacleNum;
}
if (!IsCanPass(CPoint(ptDest.x, ptDest.y - 1)))
{
++nObstacleNum;
}
if (!IsCanPass(CPoint(ptDest.x + 1, ptDest.y - 1)))
{
++nObstacleNum;
}
if (8 == nObstacleNum) //周围只有8格,如果它=8的话,就是说它周围都围满了
{
if (ptDest.y > ptSrc.y)
{
ptDest.y -= 2;
}
else
{
ptDest.y += 2;
}
if (ptDest.x > ptSrc.x)
{
ptDest.x -= 2;
}
else
{
ptDest.x += 2;
}
}
}
//将目标坐标转换成有效坐标 避免点中障碍后 没反映
//得到1 或 -1
if (!m_pnMap[ptDest.x + ptDest.y * m_MapSize.cx])
{
return;
}
int x = 0;
if (ptSrc.x != ptDest.x)
{
x = (ptSrc.x - ptDest.x)/abs(ptSrc.x - ptDest.x);
}
int y = 0;
if (ptSrc.y != ptDest.y)
{
y = (ptSrc.y - ptDest.y)/abs(ptSrc.y - ptDest.y);
}
while (m_pnMap[ptDest.x + ptDest.y * m_MapSize.cx])
{
if (ptDest.x != ptSrc.x)
{
ptDest.x = ptDest.x + x;
}
if (ptDest.y != ptSrc.y)
{
ptDest.y = ptDest.y + y;
}
}
}