C++游戏地图移动路径实现

#include "FindPath.h"

static FindPath g_FindPath;

POpenFile  *g_pOPenFile = NULL;
PCloseFile *g_pCloseFile = NULL;
PReadFile  *g_pReadFile = NULL; 
PGetFileSize  *g_pGetFileSize = NULL;

FILE * g_OpenFile(const char *psFileName,const char *psMode);
bool g_CloseFile(FILE *pFile);
size_t g_ReadFile(FILE *fp, void *buffer,size_t size);
size_t g_GetFileSize(const char *psFileName);

Log_System g_log;

extern bool GetScenePathInfo(const char * inifilename, const char * scene_res, std::string & pathfile, std::string & tgafile, SceneRect & rect);
extern bool SceneFindPath(const char * inifilename, const char * begin_sceneid,float sx,float sz,float sy, const char * end_sceneid,float dx,float dz,float dy,std::vector<SCENEPATHITEM> &pathsecene);

FILE * g_OpenFile(const char *psFileName,const char *psMode)
{
    if (g_pOPenFile == NULL)
    {
        return fopen(psFileName,psMode);
    }
    else
    {
        return (FILE *)(*g_pOPenFile)(psFileName,psMode);
    }
}

bool g_CloseFile(FILE *pFile)
{
    if (g_pCloseFile == NULL)
    {
        return fclose(pFile) == 0;
    }
    else
    {
        return (*g_pCloseFile)(pFile);
    }
}

size_t g_ReadFile(FILE *fp, void *buffer,size_t size)
{
    if (g_pReadFile == NULL)
    {
        return (int)fread(buffer, 1, size, fp);
    }
    else
    {
        return (*g_pReadFile)(fp, buffer,size);
    }
}

size_t g_GetFileSize(const char *psFileName)
{
    if (g_pGetFileSize == NULL)
    {
        FILE * fp = fopen(psFileName, "rb");
        ::fseek(fp, 0, SEEK_END);
        long size = ::ftell(fp);
        ::fseek(fp, 0, SEEK_SET);
        ::fclose(fp);

        return size;
    }
    else
    {
        return (*g_pGetFileSize)(psFileName);
    }
}

FindPath::FindPath()
{
    g_log.OpenLog();

FindPath::~FindPath()
{
    ReleaseAllPath();
}

bool FindPath::SetFileFunc(const char *FunName,void *FunPointer)
{
    if (strcmp(FunName,"OpenFile") == 0)
    {
        g_pOPenFile = (POpenFile*)FunPointer;
        return true;
    }
    if (strcmp(FunName,"CloseFile") == 0)
    {
        g_pCloseFile = (PCloseFile*)FunPointer;
        return true;
    }
    if (strcmp(FunName,"ReadFile") == 0)
    {
        g_pReadFile = (PReadFile*)FunPointer;
        return true;
    }
    if (strcmp(FunName,"GetFileSize") == 0)
    {
        g_pGetFileSize = (PGetFileSize*)FunPointer;
        return true;
    }
    return false;
}

void FindPath::InitFindPath(const char * path)
{
    m_strPath = path;
    m_IniFileName = path;
    m_IniFileName += "path_finding.ini";
}

//获得指定场景的路点总数
int FindPath::GetPathPointCount(const char * scene_res)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return 0;

    CSceneMap * pSceneMap = it->second;
    if(pSceneMap == NULL)
        return 0;

    return pSceneMap->GetPathPointCount();
}

//获得指定场景的指定区域的路点索引列表
int FindPath::GetPathPointInZone(const char * scene_res, float x, float z, float radius, int point_lst[], int max_count)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return false;

    CSceneMap * pSceneMap = it->second;
    if(pSceneMap == NULL)
        return false;

    return pSceneMap->GetPathPointInZone(x, z, radius, point_lst, max_count);
}

//获得指定场景的指定路点的信息
PATHPOINT * FindPath::GetPathPointInfo(const char * scene_res, int index)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return NULL;

    CSceneMap * pSceneMap = it->second;
    if(pSceneMap == NULL)
        return NULL;

    return pSceneMap->GetPathPointInfo(index);
}

//添加路点
int FindPath::AddPathPoint(const char * scene_res, float x, float y, float z)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return -1;

    CSceneMap * pSceneMap = it->second;
    if(pSceneMap == NULL)
        return -1;

    return pSceneMap->AddPathPoint(x, y, z);
}

//修改路点位置
bool FindPath::SetPathPointPos(const char * scene_res, int index, float x, float y, float z)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return -1;

    CSceneMap * pSceneMap = it->second;
    if(pSceneMap == NULL)
        return -1;

    return pSceneMap->SetPathPointPos(index, x, y, z);
}

//删除路点
void FindPath::RemovePathPoint(const char * scene_res, int index)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return;

    CSceneMap * pSceneMap = it->second;
    if(pSceneMap == NULL)
        return;

    pSceneMap->RemovePathPoint(index);
}

//添加连通关系
bool FindPath::AddLink(const char * scene_res, int index, int link_index)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return false;

    CSceneMap * pSceneMap = it->second;
    if(pSceneMap == NULL)
        return false;

    return pSceneMap->AddLink(index, link_index);
}

//删除连通关系
void FindPath::RemoveLink(const char * scene_res, int index, int link_index)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return;

    CSceneMap * pSceneMap = it->second;
    if(pSceneMap == NULL)
        return;

    pSceneMap->RemoveLink(index, link_index);
}

//数据是否已加载
bool FindPath::IsLoaded(const char * scene_res)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return false;

    return true;
}

bool FindPath::NewPath(const char * scene_res, ISceneMapProcess * pSceneMapProcess)
{
    if (IsLoaded(scene_res))
    {
        //数据已加载
        return false;
    }

    CSceneMap * pSceneMap = new CSceneMap(scene_res, pSceneMapProcess);
    m_mapSceneMaps.insert(std::make_pair(scene_res, pSceneMap));

    return true;
}

bool FindPath::LoadPath(const char * scene_res, ISceneMapProcess * pSceneMapProcess)
{
    g_log.wirtetime();

    if (IsLoaded(scene_res))
    {
        //数据已加载
        return false;
    }

    //加载地图
    CSceneMap * pSceneMap = new CSceneMap(scene_res, pSceneMapProcess);
    std::string full_path = m_strPath + scene_res + ".path";

    if(!pSceneMap->LoadPath(full_path.c_str()))
    {
        delete pSceneMap;
        return false;
    }

    m_mapSceneMaps.insert(std::make_pair(scene_res, pSceneMap));
    return true;
}

bool FindPath::SavePath(const char * scene_res)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return false;

    CSceneMap * pSceneMap = it->second;
    if(pSceneMap == NULL)
        return false;

    std::string full_path = m_strPath + scene_res + ".path";
    return pSceneMap->SavePath(full_path.c_str());
}

void FindPath::ReleasePath(const char * scene_res)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        //数据未加载
        return;

    CSceneMap * pSceneMap = it->second;
    if(pSceneMap != NULL)
        AW_SAFE_DELETE(pSceneMap);

    m_mapSceneMaps.erase(it);

    g_log.wirtetime();
}

void FindPath::ReleaseAllPath()
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.begin();
    for (; it != m_mapSceneMaps.end(); ++it)
        AW_SAFE_DELETE (it->second );

    m_mapSceneMaps.clear();
}

int FindPath::PointFindPath(const char * scene_res, float xBegin, float zBegin, float yBegin,
                                       float xEnd, float zEnd, float yEnd,
                                       float x[], float y[], int maxcount, bool optimize)
{
    if (maxcount < 2)
        return 0;

    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return 0;

    CSceneMap * pSceneMap = it->second;
    if(pSceneMap == NULL)
        return 0;

    if (((xBegin - xEnd) * (xBegin - xEnd) + (zBegin - zEnd) * (zBegin - zEnd)) <= DIST_VALVA*DIST_VALVA)
    {
        if(pSceneMap->TryLine(xBegin, yBegin, zBegin,xEnd, yEnd, zEnd))
        {  
            //如果两点距离比较近并且中间没有被阻挡,则直接走向目标点
            x[0] = xBegin;
            y[0] = zBegin;
            x[1] = xEnd;
            y[1] = zEnd;
            return 2;
        }
    }

    //创建地图信息
    CPathUser pathUser(pSceneMap);

    //开始寻路
    if (!pathUser.FindPath(xBegin, yBegin, zBegin,xEnd, yEnd, zEnd))
        return 0;

    int count = pathUser.GetPathPointCount();
    if (count > maxcount)
        count = maxcount;

    //把点写入用户的容器里
    if (!optimize)
    {
        //不优化处理
        for (int i = 0 ; i < count; i++)
        {
            float xtemp, ytemp, ztemp;
            pathUser.GetPathPoint(i, xtemp, ytemp, ztemp);
            x[i] = xtemp;
            y[i] = ztemp;
        }
    }
    else    
    {
        //优化处理
        //当前处理的点
        int cur_proc_index = -1;
        //当前压入的点
        int last_push_index = -1;

        while(true)
        {
            cur_proc_index++;
            if (cur_proc_index >= count)
                break;

            //取当前正在处理的点的坐标
            float xtemp, ytemp, ztemp;
            pathUser.GetPathPoint(cur_proc_index, xtemp, ytemp, ztemp);

            //是否可以丢弃最后一个被压入的点
            bool b_canreplace = false;

            if (last_push_index > 0)
            {
                //取上一个点
                float xtemp1 = x[last_push_index - 1];
                float ytemp1 = ytemp;
                float ztemp1 = y[last_push_index - 1];

                //与当前正在处理的点是否直接连通
                if (TryLine(scene_res, xtemp1, ytemp1, ztemp1, xtemp, ytemp, ztemp))
                    b_canreplace = true;
            }

            if (!b_canreplace)
                //最后一个被压入的点不可以丢弃,添加到新的位置
                last_push_index++;
            
            x[last_push_index] = xtemp;
            y[last_push_index] = ztemp;
        }

        //有效的路点数量
        count = last_push_index + 1;
    }

    return count;
}

int FindPath::SceneFindPath(const char * begin_scene_res, float xBegin, float zBegin, float yBegin,
                            const char * end_scene_res, float xEnd, float zEnd, float yEnd,
                            SCENEPATHITEM scenepath[], int maxcount)
{
    if (maxcount < 2)
        return 0;

    std::vector<SCENEPATHITEM> pathsecene;
    if(!::SceneFindPath(m_IniFileName.c_str(), begin_scene_res,xBegin,zBegin,yBegin,end_scene_res,xEnd,zEnd,yEnd,pathsecene))
        return 0;

    if (pathsecene.size() == 0)
    {
        scenepath[0].sceneid = begin_scene_res;
        scenepath[0].xBegin = xBegin;
        scenepath[0].yBegin = zBegin;
        scenepath[0].xEnd = xEnd;
        scenepath[0].yEnd = zEnd;
        return (int)pathsecene.size() + 1;
    }

    //将路点 存为输出模式(场景号,起始点,结束点)
    int count = (int)pathsecene.size();
    if (count > maxcount - 1)
        count = maxcount - 1;

    for (int i = 0 ; i <= count ; i++)
    {
        if (i == 0)
        {
            scenepath[i].sceneid = begin_scene_res;
            scenepath[i].xBegin = xBegin;
            scenepath[i].yBegin = zBegin;
            scenepath[i].xEnd = pathsecene[i].xBegin;
            scenepath[i].yEnd = pathsecene[i].yBegin;
            continue;
        }
        if (i == pathsecene.size())
        {
            scenepath[i].sceneid = end_scene_res;
            scenepath[i].xBegin = pathsecene[i - 1].xEnd;
            scenepath[i].yBegin = pathsecene[i - 1].yEnd;
            scenepath[i].xEnd = xEnd;
            scenepath[i].yEnd = zEnd;
            break;
        }
        scenepath[i].sceneid = pathsecene[i - 1].sceneid;
        scenepath[i].xBegin = pathsecene[i - 1].xEnd;
        scenepath[i].yBegin = pathsecene[i - 1].yEnd;
        scenepath[i].xEnd = pathsecene[i].xBegin;
        scenepath[i].yEnd = pathsecene[i].yBegin;
    }

    return count + 1;
}

bool FindPath::TryPoint(const char * scene_res, float x, float y, float z)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return false;
    
    CSceneMap * pSceneMap = it->second;
    if (pSceneMap == NULL)
        return false;

    return pSceneMap->TryPoint(x, y, z);
}


bool FindPath::TryLine(const char * scene_res, float xb, float yb, float zb, float xe, float ye, float ze)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return false;

    CSceneMap *pSceneMap = it->second;
    if (pSceneMap == NULL)
        return false;

    return pSceneMap->TryLine(xb, yb, zb, xe, ye, ze);
}

CSceneMap* FindPath::FindSceneMap(const char * scene_res)
{
    std::map<std::string, CSceneMap*>::iterator it = m_mapSceneMaps.find(scene_res);
    if (it == m_mapSceneMaps.end())
        return NULL;

    return (*it).second;
}

IFindPath* IFindPath::GetPointer()
{
    return &g_FindPath;
};
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

!chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值