Thank you for the past year, and good luck for the following one! Here's a little game to fill the idle moments during the holidays:
- Mottainai-1.0_OSX.zip (Mac only, sorry!)
See you next year!
Situation Agents: Agent-based Externalized Steering Logic
A Synthetic-Vision-Based Steering Approach for Crowd Simulation
dtStatus status = m_navQuery->init(m_navMesh, 2048);In many cases of success and failure, you can get one or more bits of extra information why things failed or if the quality of result is degraded. The detail flags are:
if (dtStatusFailed(status))
return false;
dtStatus status = m_navQuery->init(m_navMesh, 2048);
if (dtStatusFailed(status))
{
if (dtStatusDetail(status, DT_OUT_OF_MEMORY))
printf("Out of memory initializing navmesh query.\n");
return false;
}
dtStatus status = m_navQuery->findPath(sref, eref, spos, epos, filter, polys, &npolys, MAX_POLYS);
if (dtStatusSucceed(status))
{
if (dtStatusDetail(status, DT_BUFFER_TOO_SMALL))
// The path result is longer than MAX_POLYS.
if (dtStatusDetail(status, DT_PARTIAL_RESULT))
// Could not reach end location, the path leads to a location near the end point.
}
If you have some thoughts how you would like to integrate the multi-agent navigation to your project, please let me know!
Perturb a little to avoid deadlocks due to perfect symmetry.
static int isectSegSeg(const float* ap, const float* aq,
const float* bp, const float* bq,
float& s, float& t)
{
float u[3], v[3], w[3];
dtVsub(u,aq,ap);
dtVsub(v,bq,bp);
dtVsub(w,ap,bp);
float d = dtVperp2D(u,v);
if (fabsf(d) < 1e-6f) return 0;
d = 1.0f/d;
s = dtVperp2D(v,w) * d;
// if (s < 0 || s > 1) return 0;
t = dtVperp2D(u,w) * d;
if (t < 0 || t > 1) return 0;
return 1;
}
...
if (neighbourNode->flags == 0)
{
float sa[3], sb[3];
getPortalPoints(bestRef, bestPoly, bestTile,
neighbourRef, neighbourPoly, neighbourTile,
sa, sb);
float s,t = 0.5f;
if (!isectSegSeg(bestNode->pos,endPos, sa,sb, s, t))
dtDistancePtSegSqr2D(endPos, sa,sb, t);
t = dtClamp(t, 0.1f, 0.9f);
dtVlerp(neighbourNode->pos, sa,sb, t);
}
// If the node is visited the first time, calculate node position.
if (neighbourNode->flags == 0)
{
getEdgeMidPoint(bestRef, bestPoly, bestTile,
neighbourRef, neighbourPoly, neighbourTile,
neighbourNode->pos);
}
struct dtQueryFilter
{
dtQueryFilter() :
includeFlags(0xffff),
excludeFlags(0) {}
virtual bool passFilter(const dtPolyRef ref,
const dtMeshTile* tile,
const dtPoly* poly) const
{
return (poly->flags & includeFlags) != 0 &&
(poly->flags & excludeFlags) == 0;
}
virtual float getCost(const float* pa, const float* pb,
const dtPolyRef prevRef,
const dtMeshTile* prevTile,
const dtPoly* prevPoly,
const dtPolyRef curRef,
const dtMeshTile* curTile,
const dtPoly* curPoly) const
{
return dtVdist(pa, pb) * areaCost[curPoly->area];
}
float areaCost[DT_MAX_AREAS];
unsigned short includeFlags;
unsigned short excludeFlags;
};
rcBuildContext dummy;...rcErodeWalkableArea(&dummy, m_cfg.walkableRadius, *m_chf);
// Request
m_pathFindState = m_navQuery->initSlicedFindPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter);
...
// On update
if (m_pathFindState == DT_QUERY_RUNNING)
m_pathFindState = m_navQuery->updateSlicedFindPath(maxIter);
if (m_pathFindState == DT_QUERY_READY)
m_npolys = m_navQuery->finalizeSlicedFindPath(m_polys, MAX_POLYS);
There is new tool called "Pathfind Sliced" which allows you to see it in action. The tool advances the search one node at a time so you can see how the closed list is update in realtime.bool getTileAndPolyByRef(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
[1] Parallel Detour navigation mesh
Kingdoms of Amalur: Reckoning
I'm glad that I'm allowed to share that up coming game Kingdoms of Amalur: Reckoning by Big Huge Games is using Recast and Detour.
Google Summer of Code 2010
Thanks to Nick and Leonardo, Blender Game Engine and CrystalSpace both leveled up on pathfinding this summer.