Added better state control for tile cache obstacles.

This commit is contained in:
Mikko Mononen 2011-11-17 19:11:12 +00:00
parent bcf8b2ac03
commit d2148ff57d
2 changed files with 69 additions and 21 deletions

View File

@ -29,9 +29,10 @@ struct dtCompressedTile
enum ObstacleState enum ObstacleState
{ {
OBS_EMPTY, DT_OBSTACLE_EMPTY,
OBS_NEW, DT_OBSTACLE_PROCESSING,
OBS_PROCESSED, DT_OBSTACLE_PROCESSED,
DT_OBSTACLE_REMOVING,
}; };
static const int DT_MAX_TOUCHED_TILES = 8; static const int DT_MAX_TOUCHED_TILES = 8;
@ -39,9 +40,11 @@ struct dtTileCacheObstacle
{ {
float pos[3], radius, height; float pos[3], radius, height;
dtCompressedTileRef touched[DT_MAX_TOUCHED_TILES]; dtCompressedTileRef touched[DT_MAX_TOUCHED_TILES];
dtCompressedTileRef pending[DT_MAX_TOUCHED_TILES];
unsigned short salt; unsigned short salt;
unsigned char state; unsigned char state;
unsigned char ntouched; unsigned char ntouched;
unsigned char npending;
dtTileCacheObstacle* next; dtTileCacheObstacle* next;
}; };

View File

@ -363,7 +363,7 @@ dtObstacleRef dtTileCache::addObstacle(const float* pos, const float radius, con
unsigned short salt = ob->salt; unsigned short salt = ob->salt;
memset(ob, 0, sizeof(dtTileCacheObstacle)); memset(ob, 0, sizeof(dtTileCacheObstacle));
ob->salt = salt; ob->salt = salt;
ob->state = OBS_NEW; ob->state = DT_OBSTACLE_PROCESSING;
dtVcopy(ob->pos, pos); dtVcopy(ob->pos, pos);
ob->radius = radius; ob->radius = radius;
ob->height = height; ob->height = height;
@ -454,8 +454,6 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh)
if (req->action == REQUEST_ADD) if (req->action == REQUEST_ADD)
{ {
// Add and init obstacle.
ob->state = OBS_PROCESSED;
// Find touched tiles. // Find touched tiles.
float bmin[3], bmax[3]; float bmin[3], bmax[3];
getObstacleBounds(ob, bmin, bmax); getObstacleBounds(ob, bmin, bmax);
@ -464,29 +462,32 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh)
queryTiles(bmin, bmax, ob->touched, &ntouched, DT_MAX_TOUCHED_TILES); queryTiles(bmin, bmax, ob->touched, &ntouched, DT_MAX_TOUCHED_TILES);
ob->ntouched = (unsigned char)ntouched; ob->ntouched = (unsigned char)ntouched;
// Add tiles to update list. // Add tiles to update list.
ob->npending = 0;
for (int j = 0; j < ob->ntouched; ++j) for (int j = 0; j < ob->ntouched; ++j)
{ {
if (m_nupdate < MAX_UPDATE && !contains(m_update, m_nupdate, ob->touched[j])) if (m_nupdate < MAX_UPDATE)
m_update[m_nupdate++] = ob->touched[j]; {
if (!contains(m_update, m_nupdate, ob->touched[j]))
m_update[m_nupdate++] = ob->touched[j];
ob->pending[ob->npending++] = ob->touched[j];
}
} }
} }
else if (req->action == REQUEST_REMOVE) else if (req->action == REQUEST_REMOVE)
{ {
// Remove obstacle. // Prepare to remove obstacle.
ob->state = OBS_EMPTY; ob->state = DT_OBSTACLE_REMOVING;
// Add tiles to update list. // Add tiles to update list.
ob->npending = 0;
for (int j = 0; j < ob->ntouched; ++j) for (int j = 0; j < ob->ntouched; ++j)
{ {
if (m_nupdate < MAX_UPDATE && !contains(m_update, m_nupdate, ob->touched[j])) if (m_nupdate < MAX_UPDATE)
m_update[m_nupdate++] = ob->touched[j]; {
if (!contains(m_update, m_nupdate, ob->touched[j]))
m_update[m_nupdate++] = ob->touched[j];
ob->pending[ob->npending++] = ob->touched[j];
}
} }
// Update salt, salt should never be zero.
ob->salt = (ob->salt+1) & ((1<<16)-1);
if (ob->salt == 0)
ob->salt++;
// Return obstacle to free list.
ob->next = m_nextFreeObstacle;
m_nextFreeObstacle = ob;
} }
} }
@ -496,8 +497,52 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh)
// Process updates // Process updates
if (m_nupdate) if (m_nupdate)
{ {
dtStatus status = buildNavMeshTile(m_update[m_nupdate-1], navmesh); // Build mesh
const dtCompressedTileRef ref = m_update[0];
dtStatus status = buildNavMeshTile(ref, navmesh);
m_nupdate--; m_nupdate--;
if (m_nupdate > 0)
memmove(m_update, m_update+1, m_nupdate*sizeof(dtCompressedTileRef));
// Update obstacle states.
for (int i = 0; i < m_params.maxObstacles; ++i)
{
dtTileCacheObstacle* ob = &m_obstacles[i];
if (ob->state == DT_OBSTACLE_PROCESSING || ob->state == DT_OBSTACLE_REMOVING)
{
// Remove handled tile from pending list.
for (int j = 0; j < (int)ob->npending; j++)
{
if (ob->pending[j] == ref)
{
ob->pending[j] = ob->pending[(int)ob->npending-1];
ob->npending--;
break;
}
}
// If all pending tiles processed, change state.
if (ob->npending == 0)
{
if (ob->state == DT_OBSTACLE_PROCESSING)
{
ob->state = DT_OBSTACLE_PROCESSED;
}
else if (ob->state == DT_OBSTACLE_REMOVING)
{
ob->state = DT_OBSTACLE_EMPTY;
// Update salt, salt should never be zero.
ob->salt = (ob->salt+1) & ((1<<16)-1);
if (ob->salt == 0)
ob->salt++;
// Return obstacle to free list.
ob->next = m_nextFreeObstacle;
m_nextFreeObstacle = ob;
}
}
}
}
if (dtStatusFailed(status)) if (dtStatusFailed(status))
return status; return status;
} }
@ -550,7 +595,7 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
for (int i = 0; i < m_params.maxObstacles; ++i) for (int i = 0; i < m_params.maxObstacles; ++i)
{ {
const dtTileCacheObstacle* ob = &m_obstacles[i]; const dtTileCacheObstacle* ob = &m_obstacles[i];
if (ob->state != OBS_PROCESSED) if (ob->state == DT_OBSTACLE_EMPTY || ob->state == DT_OBSTACLE_REMOVING)
continue; continue;
if (contains(ob->touched, ob->ntouched, ref)) if (contains(ob->touched, ob->ntouched, ref))
{ {