本文是介绍对寻路库recastnavigation 改造,使得使用更加友好。
Git仓库:
https://github.com/jiangguilong2000/recastnavigation
首先,我们要做一些前置操作
SDL: 开放源代码的跨平台多媒体开发库
Premake:量跨平台构建系统
环境:
VS 2019以及完整的C++编译环境
Rider For Unreal Engine 2022.2.1(下面简称Rider)
Unity 2019.4.8 lts
.Net Core 2.2
1.首先把git库拉到本地,先将下载的SDL库放到ecastnavigation\RecastDemo\Contrib,需要改名为SDL,应该得到如下目录recastnavigation-master\RecastDemo\Contrib\SDL\lib\x64
2/然后将下载premake5.exe放入
recastnavigation\RecastDemo
3.然后通过命令行控制premake编译recastnavigation为sln工程
PS E:\recastnavigation\RecastDemo> .\premake5.exe vs2019 Building configurations... Running action 'vs2019'... Generated Build/vs2019/recastnavigation.sln... Generated Build/vs2019/DebugUtils.vcxproj... Generated Build/vs2019/DebugUtils.vcxproj.filters... Generated Build/vs2019/Detour.vcxproj... Generated Build/vs2019/Detour.vcxproj.filters... Generated Build/vs2019/DetourCrowd.vcxproj... Generated Build/vs2019/DetourCrowd.vcxproj.filters... Generated Build/vs2019/DetourTileCache.vcxproj... Generated Build/vs2019/DetourTileCache.vcxproj.filters... Generated Build/vs2019/Recast.vcxproj... Generated Build/vs2019/Recast.vcxproj.filters... Generated Build/vs2019/RecastDemo.vcxproj... Generated Build/vs2019/RecastDemo.vcxproj.user... Generated Build/vs2019/RecastDemo.vcxproj.filters... Generated Build/vs2019/Tests.vcxproj... Generated Build/vs2019/Tests.vcxproj.user... Generated Build/vs2019/Tests.vcxproj.filters... Done (160ms).
然后目录中会生成一个Build文件夹,里面是我们编译出来的sln工程
recastnavigation\RecastDemo\Build\vs2019\recastnavigation.sln
用rider打开,直接运行,我们就能看到编辑器画面了
接下去我们要对源码进行一些改造:
原始的recast是没有开始点和结束点的坐标的,那如何能显示出来呢?
void NavMeshTesterTool::handleRenderOverlay(double* proj, double* model, int* view) { GLdouble x, y, z; char buf[64]; // Draw start and end point labels if (m_sposSet && gluProject((GLdouble)m_spos[0], (GLdouble)m_spos[1], (GLdouble)m_spos[2], model, proj, view, &x, &y, &z)) { if (m_showCoord) { snprintf(buf, sizeof(buf), "Start (%.1f, %.1f, %.1f)", m_spos[0], m_spos[1], m_spos[2]); imguiDrawText((int)x, (int)(y - 25), IMGUI_ALIGN_CENTER, buf, imguiRGBA(0, 0, 0, 220)); } else imguiDrawText((int)x, (int)(y - 25), IMGUI_ALIGN_CENTER, "Start", imguiRGBA(0, 0, 0, 220)); } if (m_toolMode == TOOLMODE_RAYCAST && m_hitResult && m_showCoord && gluProject((GLdouble)m_hitPos[0], (GLdouble)m_hitPos[1], (GLdouble)m_hitPos[2], model, proj, view, &x, &y, &z)) { snprintf(buf, sizeof(buf), "HitPos (%.1f, %.1f, %.1f)", m_hitPos[0], m_hitPos[1], m_hitPos[2]); imguiDrawText((int)x, (int)(y - 25), IMGUI_ALIGN_CENTER, buf, imguiRGBA(0, 0, 0, 220)); } if (m_eposSet && gluProject((GLdouble)m_epos[0], (GLdouble)m_epos[1], (GLdouble)m_epos[2], model, proj, view, &x, &y, &z)) { if (m_showCoord) { float totalCost = 0.0f; for (int i = 0; i + 1 < m_nstraightPath; i++) totalCost += dtVdist(&m_straightPath[i * 3], &m_straightPath[(i + 1) * 3]); snprintf(buf, sizeof(buf), "End (%.1f, %.1f, %.1f), Cost %.1f", m_epos[0], m_epos[1], m_epos[2], totalCost); imguiDrawText((int)x, (int)(y - 25), IMGUI_ALIGN_CENTER, buf, imguiRGBA(0, 0, 0, 220)); } else imguiDrawText((int)x, (int)(y - 25), IMGUI_ALIGN_CENTER, "End", imguiRGBA(0, 0, 0, 220)); } }
那么,如何能显示出关键点point list?,首先,路径搜索的模式要改成TOOLMODE_PATHFIND_STRAIGHT模式,代码需要增加如下的打印,
在NavMeshTesterTool.cpp中增加,
void NavMeshTesterTool::recalc(){ .... .... if (m_toolMode == TOOLMODE_PATHFIND_STRAIGHT&& m_nstraightPath>0) { stringstream os; os << "total point size=" << m_nstraightPath<< ","; //m_sample->getContext()->log(RC_LOG_PROGRESS, "total point size=%d", m_nstraightPath); for (int i = 0; i < m_nstraightPath; ++i) { if (i > 0&&i%10==0) { m_sample->getContext()->log(RC_LOG_PROGRESS, "%s", os.str().c_str()); os.str(""); } os << "[" << m_straightPath[i * 3] << "," << m_straightPath[i * 3 + 1] << "," << m_straightPath[i * 3 + 2] << "] "; } m_sample->getContext()->log(RC_LOG_PROGRESS, "%s", os.str().c_str()); } }
在Sample.h中增加
public: Sample(); virtual ~Sample(); void setContext(BuildContext* ctx) { m_ctx = ctx; } BuildContext* getContext() { return m_ctx; }
最后一个问题,如何把显示日志的地方的文本能鼠标选中?做了个曲线救国,通过按钮复制来搞定!
//拷贝 if (imguiButton("Copy Log")) { HGLOBAL hGlobal; string allLog = ""; string prefix = "total point"; bool flag=false; for (int i = 0; i < m_sample->getContext()->getLogCount(); ++i) { string content = string(m_sample->getContext()->getLogText(i)); if(flag) { allLog += content + "\n"; }else { size_t index = content.find(prefix); if(index < content.length()) { flag=true; allLog += content + "\n"; } } } const char* content = allLog.c_str(); int bufSize = MultiByteToWideChar(CP_ACP, 0, content, -1, NULL, 0); wchar_t* wbuf = new wchar_t[bufSize]; MultiByteToWideChar(CP_ACP, 0, content, -1, wbuf, bufSize); hGlobal = GlobalAlloc(GHND, (lstrlenW(wbuf) + 1) * sizeof(wchar_t)); // lstrlenW sizeof(wchar_t) wchar_t* pGlobal = (wchar_t*)GlobalLock(hGlobal); // wchar_t lstrcpyW(pGlobal, wbuf); // lstrcpyW GlobalUnlock(hGlobal); OpenClipboard(NULL); EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, hGlobal); // UnicodeCF_UNICODETEXT CloseClipboard(); recalc(); }
效果如下:
复制出来的结果:
total point start{-31.7925,0,85.1438} end{-91.9496,0,109.848} size=6,[-31.7925,0,85.1438] [-55.1,1.6,104.598] [-56.3,2,105.498] [-61.1,2.4,107.298] [-65.6,1.6,107.898] [-91.9496,0,109.848]